ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

基于 tfjs-tsne 的浏览器端 GPU 加速 t-SNE 实战:MNIST 手写数字二维降维可视化

基于 tfjs-tsne 的浏览器端 GPU 加速 t-SNE 实战:MNIST 手写数字二维降维可视化 示例工程【免费下载链接】tfjs-examplesExamples built with TensorFlow.js项目地址https://gitcode.com/gh_mirrors/tf/tfjs-examples点击查看免费下载本指南围绕 tfjs-examples 仓库中的tsne-mnist-canvas示例讲解如何借助 TensorFlow.js 生态下的 tfjs-tsne 库在浏览器中完成 MNIST 手写数字数据集的 t-SNE 降维与实时可视化。读完本文你将掌握 MNIST 数据的加载与张量预处理管线、tfjs-tsne 的 kNN 与迭代式嵌入 API、基于 d3 与 Canvas 2D 的坐标渲染方案以及 WebGL 2 环境要求与关键参数的调优方向。示例概览在浏览器里跑通完整的 t-SNE 流程正如 README.md 所描述的本示例演示了使用tfjs-tsne库对 MNIST 数据集 做降维从测试集中取出10000 张手写数字图片将其缩放为10×10 像素再用t-SNE 算法把它们组织到二维平面上让相同数字在空间上聚成簇、不同数字彼此分离从而直观地检验高维图像数据在低维空间中的结构。演示页面的标题正是“GPU Accelerated T-SNE in the Browser”整个计算过程依托 TensorFlow.js 与 WebGL 在 GPU 上完成这也是本示例区别于传统 CPU 版 t-SNE 工具的核心亮点。该示例的仓库结构十分精简只有 6 个文件tsne-mnist-canvas/ ├── README.md # 示例说明与运行命令 ├── index.html # 页面结构、参数控件与样式 ├── index.js # 主逻辑数据预处理、t-SNE 调用、渲染 ├── data.js # MnistData 类MNIST 数据加载与切分 ├── package.json # 依赖与构建脚本 └── yarn.lock # 依赖锁定文件运行环境前提必须支持 WebGL 2README 给出了一个重要但容易被忽略的环境限制tfjs-tsne requires WebGL 2 support and thus will not work on certain devices, mobile devices especially. Currently it best works on desktop devices.也就是说tfjs-tsne依赖WebGL 2支持因此移动设备上很可能无法运行尤其是部分只支持 WebGL 1 的手机浏览器桌面端浏览器体验最佳建议在较新的 Chrome / Firefox / Edge 等支持 WebGL 2 的桌面浏览器中运行。从实现上可以推断该限制源于 tfjs-tsne 将 kNN 近邻图构建与 t-SNE 优化等重计算全部放在 GPU 着色器shader中执行以获得实时的迭代可视化体验而 WebGL 2 提供了所需的更灵活的浮点纹理与计算能力。因此如果运行页面时出现空白或报错请先确认浏览器支持 WebGL 2。快速运行两条命令启动README 给出的启动方式只有两条命令yarn yarn watchyarn安装依赖依赖清单见 package.jsontensorflow/tfjs^1.3.2、tensorflow/tfjs-tsne0.2.0、d3^5.2.0yarn watch启动开发服务器并在浏览器中自动打开页面官方同时在 GCS 上托管了在线演示版本可直接访问体验。package.json中完整定义了三个脚本可满足开发与构建两种场景scripts: { watch: NODE_ENVdevelopment parcel index.html --no-hmr --open, build: NODE_ENVproduction parcel build --no-scope-hoist index.html --public-url ./, link-local: yalc link }yarn watch基于Parcel的本地开发模式--no-hmr关闭热模块替换避免开发中频繁整页刷新--open自动打开浏览器yarn build产出生产构建--public-url ./保证资源使用相对路径方便部署到任意静态目录yarn link-local配合 devDependencies 中的yalc用于本地链接尚未发布的 tfjs-tsne 版本属于库作者联调场景。数据准备从 MNIST 精灵图加载训练与测试集数据层由 data.js 中的MnistData类负责它直接从云存储加载两份 MNIST 原始资源一张把全部 65000 张图片纵向拼接的精灵图sprite以及一份 uint8 格式的标签文件。关键常量见 data.jsconst IMAGE_SIZE 784; // 28×28 784 像素 const NUM_CLASSES 10; // 0~9 十个数字类别 const NUM_DATASET_ELEMENTS 65000; // 全量样本数 const NUM_TRAIN_ELEMENTS 55000; // 训练集 const NUM_TEST_ELEMENTS 10000; // 测试集load()方法的核心加载流程值得注意用Image对象加载精灵图并设置crossOrigin 以跨域读取像素以chunkSize 5000为步长分块绘制到临时 canvas 上再通过getImageData取出像素——由于 MNIST 是灰度图只需读取红色通道并除以 255 完成归一化见 data.js并行fetch标签文件解析为Uint8Array用tf.util.createShuffledIndices生成乱序索引并将图像与标签按 55000 / 10000 切分为trainImages、testImages、trainLabels、testLabels见 data.js。本示例只用到测试集因此在 index.js 中仅需一行async function loadData() { data new MnistData(); return data.load(); }预处理张量管线28×28 图像降维到 10×10 特征这是整个示例中最有工程价值的一段在送入 t-SNE 之前把高维输入压缩到可控维度。start函数见 index.js在tf.tidy作用域内完成全部张量操作const [reshaped, labels] tf.tidy(() { // 1. 标签one-hot 转成数字数组 const labelsTensor tf.tensor2d(data.testLabels, [NUM_IMAGES, NUM_CLASSES]); const labels labelsTensor.argMax(1).dataSync(); // 2. 图像构建 [10000, 28, 28, 1] 张量并截取前 numPoints 张 const images tf.tensor4d(data.testImages, [ NUM_IMAGES, IMG_HEIGHT, IMG_WIDTH, 1 ]).slice([0], [numPoints]); // 3. 缩放双线性插值到 10×10 const resized images.resizeBilinear([NEW_HEIGHT, NEW_WIDTH]); // 4. 重塑摊平为 tfjs-tsne 期望的 rank-2 输入 const reshaped resized.reshape([numPoints, NEW_HEIGHT * NEW_WIDTH]); return [reshaped, labels]; });各步骤的作用标签转换MNIST 标签是 one-hot 编码的[10000, 10]张量用argMax(1)取每行最大值下标得到[10000]的数字标签数组供后续按类别着色切片slice([0], [numPoints])从测试集中取用户指定的样本数默认 10000双线性缩放resizeBilinear([10, 10])把每张 28×28 图像缩小到 10×10将特征维度从 784 降到100这既大幅降低了 t-SNE 的计算量又不至于损失过多的数字结构信息重塑reshape([numPoints, 100])得到 tfjs-tsne 要求的 rank-2 输入张量[样本数, 特征数]。最后tf.tidy自动回收中间张量函数末尾还显式调用reshaped.dispose()释放输入张量避免 GPU 显存泄漏——在动辄 10000 行样本的降维任务里内存管理是保持页面流畅的必要细节。t-SNE 计算流程tfjs-tsne 的核心调用链doEmbedding函数见 index.js完整展示了 tfjs-tsne 的异步 API 用法整个流程分为两阶段async function doEmbedding( data, labels, numIterations, knnIter, perplexity, onIteration) { // 阶段一创建 embedder 并预计算 kNN 近邻图 const embedder tsne.tsne(data); await embedder.iterateKnn(knnIter); // 阶段二逐轮迭代优化并在每轮之间渲染当前坐标 for (let i 0; i numIterations; i) { await embedder.iterate(1); const coordinates await embedder.coordsArray(); onIteration(coordinates, labels); await tf.nextFrame(); } }逐行拆解tsne.tsne(data)传入[样本数, 100]的张量创建一个 GPU 加速的 t-SNE embedder 实例await embedder.iterateKnn(knnIter)正式优化前先执行若干轮 kNNk 近邻迭代构建样本之间的近邻关系图这是 t-SNE 计算相似度矩阵的基础await embedder.iterate(1)执行一轮 t-SNE 梯度优化迭代。示例刻意每轮只迭代 1 次代码注释明确说明“你也可以在两次取坐标渲染之间多迭代几次”——这样可以在迭代尚未收敛时就展示中间状态形成渐进式动画await embedder.coordsArray()从 GPU 取回当前所有样本的二维坐标数组交给渲染回调await tf.nextFrame()把控制权交还给浏览器渲染线程避免长循环阻塞页面是浏览器端异步计算中保持 UI 流畅的关键一步。实时渲染d3 与 Canvas 2D 画出手写数字散点renderEmbedding见 index.js负责把坐标绘制到 800×800 的 canvas 上采用d3 缩放 Canvas 2D 逐点绘制的组合function renderEmbedding(coordinates, labels) { const x d3.scaleLinear().range([0, width]).domain([0, 1]); const y d3.scaleLinear().range([0, height]).domain([0, 1]); context.clearRect(0, 0, width, height); coordinates.forEach(function(d, i) { context.font 10px sans; context.fillStyle colors(parseInt(labels[i], 10)); context.fillText(labels[i], x(d[0]), y(d[1])); }); }渲染细节坐标映射d3.scaleLinear把坐标从[0, 1]区间线性映射到画布像素范围——从 domain 取值可以推断coordsArray()返回的坐标被归一化在[0, 1]内逐点着色colors d3.scaleOrdinal(d3.schemeCategory10)见 index.js为 10 个数字类别各分配一种颜色直接绘制数字字符每个样本用fillText绘制它自身的标签数字0~9因此不依赖额外的点/图片资源几万点也能在 10px 字号下保持清晰的散点分布逐帧重绘每轮 t-SNE 迭代都会clearRect后重新绘制全部坐标可视化出“点云逐步聚成 10 团”的动态过程。canvas 本身由initVisualization在#vis容器内动态创建并获取 2d context见 index.js样式上通过 1px 黑色边框与页面布局区分可视化区域。交互控件与参数调优index.html 提供了一组滑块与单选按钮initControls见 index.js在数据加载完成后将其启用。点击Start T-SNE按钮后读取全部参数并调用start(numPoints, tsneIter, knnIter, perplexity)按钮文字随之变为Restart TSNE可反复调整参数重跑。全部可调参数及默认值如下控件含义取值范围默认值Perplexityt-SNE 的核心超参数控制每个点周围“有效近邻”的数量用于平衡局部与全局结构2 ~ 42步长 130KNN Iterations正式优化前构建 kNN 近邻图的迭代轮数决定相似度矩阵的质量2 ~ 1500步长 1800T-SNE Iterations进入 t-SNE 优化阶段后的总迭代轮数决定嵌入结果的收敛程度1 ~ 1000步长 1500Number of Digits实际参与降维的样本数对应numPoints参数500 / 2000 / 10000单选10000调参方向可以这样把握以下为 t-SNE 通用经验可作为调试参考Perplexity从算法原理看值越大越侧重保留全局结构值越小越侧重局部结构对 500 个样本的小数据集过大的 perplexity 会引入偏差通常可相应调低KNN Iterations迭代越多近邻图越准确但耗时线性增长。若聚类结果明显杂乱可优先增大该项T-SNE Iterations迭代越多收敛越好但每轮都要在 GPU 上更新并回读坐标。本示例每轮只iterate(1)并立即渲染因此总迭代数也直接决定动画时长样本数10000 点最能展现 MNIST 的完整结构但计算与渲染开销最大调试阶段可用 500 或 2000 快速验证参数效果。另外控件区域的所有input[typerange]滑块都会在滑动时实时把当前值回显到其前的span标签中见 index.js方便观察所选数值。小结一条完整的浏览器端降维链路tsne-mnist-canvas用约百行核心代码串起了从数据加载、张量预处理、GPU 加速 t-SNE 到 Canvas 实时渲染的完整链路是理解 tfjs-tsne 用法的理想起点。回顾本文要点环境tfjs-tsne 依赖 WebGL 2移动端兼容性有限桌面浏览器体验最佳数据data.js 展示了从精灵图异步加载 MNIST 并进行 train/test 切分的完整写法预处理index.js 通过slice → resizeBilinear → reshape把 28×28 图像压缩为 10×10100 维特征并借助tf.tidy管理 GPU 内存计算tsne.tsne → iterateKnn → iterate(1) → coordsArray → tf.nextFrame两阶段调用链兼顾了收敛质量与 UI 流畅度渲染d3 比例尺 Canvas 逐点fillText的方案支持数万点的实时动画。如需深入可继续阅读仓库中 data.js、index.js 与 index.html 的完整实现并对照 package.json 了解依赖版本与构建脚本即可在此基础上替换为自己的数据集搭建浏览器端的通用高维数据探索工具。赞分享示例工程【免费下载链接】tfjs-examplesExamples built with TensorFlow.js项目地址https://gitcode.com/gh_mirrors/tf/tfjs-examples点击查看免费下载相关推荐3步并行开发Prime Agent Subagent 子智能体实战指南3步并行开发Prime Agent Subagent 子智能体实战指南 认证模块要改、测试要补、审查任务还堆着主智能体只能一件件串行干。Prime Agen人工智能AI Agent代码智能体工具调用交互助手MCP ClientsAgent 记忆2024年最受欢迎的流媒体代理工具Threadfin核心功能全解析2024年最受欢迎的流媒体代理工具Threadfin核心功能全解析 Threadfin 是一款基于 xTeVe 开发的 M3U 代理工具专为 Kernel、后端音视频Plotly 可视化 t-SNE 与 UMAP 降维投影从高维数据到 2D/3D 散点图实战基于 plotly.pyPlotly 可视化 t SNE 与 UMAP 降维投影从高维数据到 2D/3D 散点图实战基于 plotly.py 本篇技术指南以 doc/python数据可视化数据分析上一篇AlphaFold 3革命性蛋白质结构预测的7大关键技术突破与实战指南下一篇gh_mirrors/de/developer组件设计构建可复用UI创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表