index.html 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. <html>
  2. <head>
  3. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  4. <style>
  5. #result { font-size: 48px; }
  6. #time { font-size: 16px; color: grey; }
  7. #mybox { padding: 20px; }
  8. #resultbox { padding: 50px; }
  9. .bigggg { font-size: 18px; margin-top: 10px; }
  10. .bigg { font-size: 18px; }
  11. #url { font-size: 18px; width: 70%; }
  12. a { text-decoration: none; }
  13. h1 { padding: 50px; padding-bottom: 0px; font-size: 36px; font-weight: normal; }
  14. #imagebox { height:224px; width:224px; border: 1px dotted black; }
  15. #video { height:0px; width:0px; border: 1px dotted black; object-fit: cover;}
  16. canvas { display: none; }
  17. * { text-align: center; font-family: monospace; }
  18. </style>
  19. <title>tinygrad has WebGPU</title>
  20. <script src="./net.js"></script>
  21. <link rel="icon" type="image/x-icon" href="https://raw.githubusercontent.com/tinygrad/tinygrad/master/docs/logo.png">
  22. </head>
  23. <body>
  24. <h1>WebGPU <a href="https://github.com/geohot/tinygrad">tinygrad</a> EfficientNet!</h1>
  25. <div id="mybox">
  26. <input type="text" id="url" placeholder="put url here" value="https://upload.wikimedia.org/wikipedia/commons/d/da/Norwegian_hen.jpg">
  27. <input class="bigg" type="button" onclick="runNetWResource(document.getElementById('url').value)" value="Use URL">
  28. </div>
  29. <br/>
  30. <img id="imagebox"></img>
  31. <canvas id="canvas" width="200" height="200"> </canvas>
  32. <div id="resultbox">
  33. <div id="result">result will go here</div>
  34. <div id="time"></div>
  35. </div>
  36. <script>
  37. const ctx = document.getElementById("canvas").getContext("2d", { willReadFrequently: true });
  38. const resultText = document.getElementById('result');
  39. let labels, net;
  40. const error = (err) => {
  41. resultText.innerHTML = `Error: ${err}`;
  42. throw new Error(err);
  43. }
  44. const getDevice = async () => {
  45. if (!navigator.gpu) error("WebGPU not supported.");
  46. const adapter = await navigator.gpu.requestAdapter();
  47. return await adapter.requestDevice();
  48. };
  49. const timer = async (func, label = "") => {
  50. document.getElementById('time').innerHTML = "";
  51. const start = performance.now();
  52. const out = await func();
  53. const delta = (performance.now() - start).toFixed(1)
  54. console.log(`${delta} ms ${label}`);
  55. document.getElementById('time').innerHTML = `${delta} ms ${label}`;
  56. return out;
  57. }
  58. const getLabels = async () => (await fetch("https://raw.githubusercontent.com/anishathalye/imagenet-simple-labels/master/imagenet-simple-labels.json")).json();
  59. const getSavetensorBuffer = async () => new Uint8Array(await (await fetch("./net.safetensors")).arrayBuffer());
  60. const reorderChannelsAndRemoveAlpha = (data) => {
  61. const out = [];
  62. let i = 0;
  63. for (let c = 0; c < 3; c++) {
  64. for (let x = 0; x < 224 * 224; x++) {
  65. out[i] = data[x * 4 + c];
  66. i++;
  67. }
  68. }
  69. return out;
  70. };
  71. const runNetWResource = async (resource) => {
  72. resultText.innerHTML = "pending..."
  73. if (resource == "") error("sir. please type in a URL");
  74. const response = await fetch(resource)
  75. if (!response.ok) error("sir. that is not a good URL. try a new one");
  76. document.getElementById("imagebox").src = resource
  77. const img = new Image();
  78. img.crossOrigin = "Anonymous";
  79. img.onload = () => {
  80. URL.revokeObjectURL(img.src);
  81. ctx.drawImage(img, 0, 0, 224, 224);
  82. const data = ctx.getImageData(0, 0, 224, 224).data;
  83. runNet(data)
  84. };
  85. img.src = resource;
  86. }
  87. const loadLet = async () => {
  88. try {
  89. resultText.innerHTML = "loading..."
  90. labels = await getLabels();
  91. const safetensor = await getSavetensorBuffer();
  92. const device = await getDevice();
  93. net = await timer(() => setupNet(device, safetensor), "(compilation)");
  94. resultText.innerHTML = "ready"
  95. } catch (e) {
  96. error(e)
  97. }
  98. }
  99. const runNet = async (data) => {
  100. if (!net) error("Net not loaded yet.");
  101. const input = reorderChannelsAndRemoveAlpha(Array.from(data).map((pix) => (pix / 255.0) * 0.45 - 0.225));
  102. const out = await timer(() => net(new Float32Array(input)));
  103. const arr = Array.from(new Float32Array(out[0]));
  104. const index = arr.indexOf(Math.max(...arr));
  105. resultText.textContent = labels[index];
  106. };
  107. loadLet();
  108. </script>
  109. </body>
  110. </html>