{"id":706738,"student_id":2589,"content":"{\"html\":\"\u003c!DOCTYPE html\u003e\\n\u003chtml lang=\\\"en\\\"\u003e\\n\\n\u003chead\u003e\\n \u003cmeta charset=\\\"UTF-8\\\"\u003e\\n \u003cmeta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1.0\\\"\u003e\\n \u003ctitle\u003ehandwriting recognition\u003c/title\u003e\\n \u003cscript src=\\\"https://cdn.jsdelivr.net/npm/chart.js\\\"\u003e\u003c/script\u003e\\n \u003clink href=\\\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css\\\" rel=\\\"stylesheet\\\"\u003e\\n \u003cscript src=\\\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js\\\"\u003e\u003c/script\u003e\\n \u003cscript src=\\\"https://code.jquery.com/jquery-3.7.1.min.js\\\"\u003e\u003c/script\u003e\\n\u003c/head\u003e\\n\\n\u003cbody\u003e\\n \u003cdiv class=\\\"container py-3\\\"\u003e\\n \u003cdiv class=\\\"row\\\"\u003e\\n \u003cdiv class=\\\"col-8\\\"\u003e\\n \u003cdiv class=\\\"overflow-x-scroll bg-dark\\\"\u003e\\n \u003cdiv class=\\\"position-relative\\\"\u003e\\n \u003cdiv id=\\\"cursor\\\" class=\\\"position-absolute\\\"\\n style=\\\"width: 28px; height: 28px; top:0; left: 0; z-index: 10; border: 2px solid red;\\\"\u003e\u003c/div\u003e\\n \u003ccanvas id=\\\"mark-canvas\\\" width=\\\"28000\\\" height=\\\"280\\\" class=\\\"position-absolute top-0 left-0\\\"\\n style=\\\"opacity: 0.6;\\\"\u003e\u003c/canvas\u003e\\n \u003ccanvas id=\\\"data-canvas\\\" width=\\\"28000\\\" height=\\\"280\\\" style=\\\"image-rendering: pixelated;\\\"\u003e\u003c/canvas\u003e\\n \u003c/div\u003e\\n \u003c/div\u003e\\n \u003cdiv\u003e\\n \u003ccanvas id=\\\"chart-canvas\\\"\u003e\u003c/canvas\u003e\\n \u003ccanvas id=\\\"brain-canvas\\\" width=\\\"1200\\\" height=\\\"600\\\"\u003e\u003c/canvas\u003e\\n \u003c/div\u003e\\n \u003c/div\u003e\\n \u003cdiv class=\\\"col-4\\\"\u003e\\n \u003ccanvas id=\\\"draw-canvas\\\" width=\\\"28\\\" height=\\\"28\\\" class=\\\"border bg-black\\\"\\n style=\\\"width: 280px; image-rendering: pixelated;\\\"\u003e\u003c/canvas\u003e\\n \u003ccanvas id=\\\"mini-canvas\\\" width=\\\"28\\\" height=\\\"28\\\" class=\\\"border bg-black d-none\\\"\u003e\u003c/canvas\u003e\\n\\n \u003cdiv class=\\\"mb-2\\\"\u003e\\n \u003cdiv class=\\\"btn-group btn-group-sm\\\"\u003e\\n \u003cbutton class=\\\"btn btn-dark\\\" id=\\\"next\\\"\u003e寫入並右移\u003c/button\u003e\\n \u003cbutton class=\\\"btn btn-dark\\\" id=\\\"clear\\\"\u003e清除畫布\u003c/button\u003e\\n \u003cbutton class=\\\"btn btn-dark\\\" id=\\\"detect\\\"\u003e偵測畫布\u003c/button\u003e\\n \u003c/div\u003e\\n \u003c/div\u003e\\n\\n \u003cdiv class=\\\"mb-2\\\"\u003e\\n \u003cdiv class=\\\"btn-group btn-group-sm\\\"\u003e\\n \u003cbutton class=\\\"btn btn-dark\\\" onclick=\\\"download()\\\"\u003e下載圖片\u003c/button\u003e\\n \u003cbutton class=\\\"btn btn-dark\\\" onclick=\\\"upload()\\\"\u003e上傳圖片\u003c/button\u003e\\n \u003cbutton class=\\\"btn btn-dark\\\" onclick=\\\"clearDataCanvas()\\\"\u003e清除所有資料\u003c/button\u003e\\n \u003c/div\u003e\\n \u003c/div\u003e\\n\\n \u003cdiv class=\\\"mb-2\\\"\u003e\\n \u003cbutton class=\\\"btn btn-success\\\" id=\\\"start\\\"\u003e開始訓練\u003c/button\u003e\\n \u003c/div\u003e\\n \u003cpre class=\\\"alert alert-secondary w-100 overflow-y-scroll\\\" style=\\\"height: 200px;\\\" id=\\\"logger\\\"\u003e\u003c/pre\u003e\\n \u003c/div\u003e\\n \u003c/div\u003e\\n \u003c/div\u003e\\n\\n \u003cscript src=\\\"day2.js\\\"\u003e\u003c/script\u003e\\n\\n \u003cscript\u003e\\n var SIZE = 28\\n var dataCanvas = $('#data-canvas')[0]\\n var dataCtx = dataCanvas.getContext('2d')\\n var drawCanvas = $('#draw-canvas')[0]\\n var drawCtx = drawCanvas.getContext('2d')\\n var markCanvas = $('#mark-canvas')[0]\\n var markCtx = markCanvas.getContext('2d')\\n var miniCanvas = $('#mini-canvas')[0]\\n var miniCtx = miniCanvas.getContext('2d')\\n\\n var cursorX = 0\\n var cursorY = 0\\n var isMouseDown = false\\n \\n initDataCanvas();\\n loadCache();\\n \\n function initDataCanvas() {\\n dataCtx.fillStyle = 'back'\\n dataCtx.fillRect(0, 0, 28000, 280);\\n }\\n \\n function clearDataCanvas() {\\n if (confirm('確定要清除?')) {\\n initDataCanvas();\\n localStorage.setItem('image', '');\\n }\\n }\\n\\n function loadCache() {\\n var dataURL = localStorage.getItem('image')\\n var img = new Image\\n img.src = dataURL\\n img.onload = () =\u003e dataCtx.drawImage(img, 0, 0)\\n }\\n \\n function loadImage(src) {\\n var img = new Image\\n img.onload = () =\u003e dataCtx.drawImage(img, 0, 0)\\n img.src = src\\n }\\n\\n function download() {\\n var link = document.createElement('a')\\n link.download = 'backup.png';\\n link.href = dataCanvas.toDataURL('image/png')\\n link.click();\\n }\\n\\n function upload() {\\n const fileInput = document.createElement('input')\\n fileInput.type = 'file'\\n fileInput.addEventListener('change', (event) =\u003e {\\n const file = event.target.files[0]\\n const reader = new FileReader()\\n reader.onload = (e) =\u003e {\\n const img = new Image()\\n img.onload = () =\u003e dataCtx.drawImage(img, 0, 0)\\n img.src = e.target.result\\n }\\n reader.readAsDataURL(file)\\n })\\n fileInput.click()\\n }\\n\\n function handleFileSelect() {\\n const file = event.target.files[0]\\n }\\n\\n var chart = new Chart($('#chart-canvas')[0], {\\n type: 'line',\\n data: {\\n labels: [],\\n datasets: [\\n { label: '訓練資料通過率', borderWidth: 2 },\\n { label: '測試資料通過率', borderWidth: 2 },\\n ]\\n },\\n options: {\\n elements: { point: { radius: 0 } },\\n scales: { y: { beginAtZero: true, min: 0, max: 100 } },\\n animation: { duration: 0 },\\n }\\n })\\n\\n var isTraining = false\\n $('#start').click(() =\u003e {\\n $('#start').toggleClass('btn-success')\\n $('#start').toggleClass('btn-danger')\\n $('#start').text(isTraining ? '開始訓練' : '停止訓練')\\n isTraining ? stop() : start()\\n isTraining = !isTraining\\n })\\n $('#stop').click(() =\u003e window.stop())\\n $('#detect').click(() =\u003e window.detect())\\n $('#saveback').click(() =\u003e window.saveback())\\n\\n $('#next').click(() =\u003e {\\n saveback()\\n cursorX += 1\\n loadFromData()\\n $('#cursor').css({ top: `${cursorY * SIZE}px`, left: `${cursorX * SIZE}px` })\\n })\\n\\n $('#draw-canvas').on('mousedown', () =\u003e isMouseDown = true)\\n $('#draw-canvas').on('mouseup', () =\u003e isMouseDown = false)\\n $('#draw-canvas').on('mousemove', (e) =\u003e {\\n if (!isMouseDown) return\\n var rect = drawCanvas.getBoundingClientRect()\\n var x = Math.floor((e.clientX - rect.left) / 10)\\n var y = Math.floor((e.clientY - rect.top) / 10)\\n drawCtx.fillStyle = 'white'\\n drawCtx.beginPath()\\n drawCtx.arc(x, y, 1, 0, 3 * Math.PI)\\n drawCtx.fill()\\n })\\n $('#mark-canvas').click(e =\u003e {\\n var rect = dataCanvas.getBoundingClientRect()\\n cursorX = Math.floor((e.clientX - rect.left) / SIZE)\\n cursorY = Math.floor((e.clientY - rect.top) / SIZE)\\n loadFromData()\\n $('#cursor').css({ top: `${cursorY * SIZE}px`, left: `${cursorX * SIZE}px` })\\n })\\n $('#upload').change(e =\u003e {\\n var img = new Image()\\n img.onload = () =\u003e dataCtx.drawImage(img, 0, 0)\\n img.src = URL.createObjectURL(e.target.files[0])\\n })\\n $('#clear').click(() =\u003e {\\n drawCtx.fillStyle = 'black'\\n drawCtx.fillRect(0, 0, SIZE, SIZE)\\n })\\n\\n function loadFromData() {\\n drawCtx.clearRect(0, 0, SIZE, SIZE)\\n drawCtx.drawImage(dataCanvas, cursorX * SIZE, cursorY * SIZE, SIZE, SIZE, 0, 0, SIZE, SIZE)\\n }\\n\\n function saveback() {\\n dataCtx.drawImage(drawCanvas, 0, 0, SIZE, SIZE, cursorX * SIZE, cursorY * SIZE, SIZE, SIZE)\\n var data = dataCanvas.toDataURL('image/jpg')\\n localStorage.setItem('image', data)\\n }\\n\\n function getHandDrawnData() {\\n var arr = []\\n miniCtx.drawImage(drawCanvas, 0, 0, SIZE, SIZE)\\n var data = miniCtx.getImageData(0, 0, SIZE, SIZE).data\\n for (var i = 0; i \u003c data.length; i += 4) {\\n ;\\n var avg = (data[i + 0] + data[i + 1] + data[i + 2]) / 3 / 225\\n arr.push(avg)\\n }\\n return arr\\n }\\n\\n function getImageData(x, y, width, height) {\\n var list = []\\n var data = dataCtx.getImageData(x, y, width, height).data\\n for (var i = 0; i \u003c data.length; i += 4) {\\n var avg = (data[i + 0] + data[i + 1] + data[i + 2]) / 3 / 225\\n list.push(avg)\\n }\\n return list\\n }\\n\\n function addLog(content) {\\n $('#logger').prepend(`\u003cspan\u003e${JSON.stringify(content)}\u003c/span\u003e\u003cbr/\u003e`)\\n }\\n\\n function chartLog(trainRate, testRate) {\\n chart.data.labels.push(chart.data.labels.length + 1)\\n chart.data.datasets[0].data.push(trainRate)\\n chart.data.datasets[1].data.push(testRate)\\n chart.update()\\n }\\n\\n \u003c/script\u003e\\n\\n\u003c/body\u003e\\n\\n\u003c/html\u003e\",\"css\":\"\",\"js\":\"// 產生指定長度的陣列\\nfunction makeArray(x) {\\n return (new Array(x)).fill(0);\\n}\\n\\n// 產生指定長寬的矩陣,用來作為神經層之間的權重\\nfunction makeMatrix(x, y) {\\n var grid = makeArray(x);\\n return grid.map(_ =\u003e makeArray(y).map(rand));\\n}\\n\\n// 產生 -0.5 至 0.5 之間的隨機小數\\nfunction rand() {\\n return Math.random() - 0.5;\\n}\\n\\n// 激活函式\\nfunction sigmoid(x) {\\n return Math.tanh(x);\\n}\\n\\n// 激活函式導數\\nfunction dsigmoid(x) {\\n return 1 - x * x;\\n}\\n\\n// 矩陣相乘,用來作為正向傳遞的計算\\nfunction dot(arr, mx) {\\n var list = makeArray(mx[0].length);\\n for (var i = 0; i \u003c mx[0].length; i++) {\\n for (var j = 0; j \u003c arr.length; j++) {\\n list[i] += arr[j] * mx[j][i];\\n }\\n }\\n return list;\\n}\\n\\n// 矩陣反轉,用來作為反向傳遞的計算\\nfunction transpose(mx) {\\n return mx[0].map((_, i) =\u003e mx.map(row =\u003e row[i]));\\n}\\n\\n// 根據誤差更新神經網路的矩陣\\nfunction updateWeight(mx, arr1, arr2, rate = 0.01) {\\n for (var i = 0; i \u003c arr1.length; i++) {\\n for (var j = 0; j \u003c arr2.length; j++) {\\n mx[i][j] += arr1[i] * arr2[j] * rate;\\n }\\n }\\n}\\n\\n// ------------------------------------------------------------- //\\n\\nfunction NN(a, b, c, d) {\\n \\n var n1 = makeArray(a); //第 1 層神經儲存的數值 \\n var n2 = makeArray(b); //第 2 層神經儲存的數值\\n var n3 = makeArray(c); //第 3 層神經儲存的數值\\n var n4 = makeArray(d); //第 4 層神經儲存的數值\\n var w1 = makeMatrix(a, b); //第 1, 2 層神經之間的權重\\n var w2 = makeMatrix(b, c); //第 2, 3 層神經之間的權重\\n var w3 = makeMatrix(c, d); //第 3, 4 層神經之間的權重\\n\\n // 正向傳遞\\n function forward(inputs) {\\n n1 = inputs;\\n n2 = dot(n1, w1).map(sigmoid);\\n n3 = dot(n2, w2).map(sigmoid);\\n n4 = dot(n3, w3).map(sigmoid);\\n return n4\\n }\\n\\n // 反向傳遞\\n function backward(target, learningRate = 0.001) {\\n var e4 = target.map((t, i) =\u003e t - n4[i]);\\n var d4 = n4.map(dsigmoid).map((v, i) =\u003e v * e4[i]);\\n var e3 = dot(d4, transpose(w3));\\n var d3 = n3.map(dsigmoid).map((v, i) =\u003e v * e3[i]);\\n var e2 = dot(d3, transpose(w2));\\n var d2 = n2.map(dsigmoid).map((v, i) =\u003e v * e2[i]);\\n updateWeight(w3, n3, d4, learningRate);\\n updateWeight(w2, n2, d3, learningRate);\\n updateWeight(w1, n1, d2, learningRate);\\n }\\n\\n return { forward, backward }\\n}\\n\\n// ------------------------------------------------------------- //\\n\\nvar training = false; //是否正在訓練\\nvar trainData = []; //訓練資料\\nvar testData = []; //測試資料\\n\\nvar LABEL = 3; //讀取資料的高度\\nvar LENGTH = 10; //讀取資料的長度\\nvar CUT = 10; //切割資料長度,區分訓練和測試\\n\\nvar nn = NN(28*28, 8, 8, 3);\\n\\nfunction detect() {\\n var input = getHandDrawnData();\\n var output = nn.forward(input); // 784 inputs\\n var num = output.indexOf(Math.max(...output));\\n addLog('偵測結果:' +num);\\n}\\n\\n// 點擊「開始訓練」按鈕觸發此程式\\nfunction start() {\\n training = true;\\n trainData = []; //清除訓練資料\\n testData = []; //清除測試資料\\n \\n for(var x=0; x\u003c10; x++) {\\n for(var y=0; y\u003c3; y++) {\\n var input = getImageData(28*x, 28*y, 28, 28);\\n var target = makeArray(10);\\n target[y] = 1;\\n trainData.push({ input, target});\\n }\\n }\\n \\n loop(); // 開始訓練迴圈\\n}\\n\\n// 點擊「暫停訓練」按鈕觸發此程式\\nfunction stop() {\\n training = false;\\n}\\n\\n// 訓練的迴圈\\nfunction loop() {\\n markCtx.clearRect(0, 0, 28000, 420); //清除標記\\n \\n var trainPass = train(trainData); //訓練\\n var trainPct = Math.floor(trainPass * 100 / trainData.length); //計算訓練通過率\\n addLog(\\\"訓練通過率: \\\"+ trainPct +\\\"%\\\");\\n \\n if (training) setTimeout(loop, 100);\\n}\\n\\n// 執行訓練資料\\nfunction train(data) {\\n var count = 0;\\n for(var i=0; i\u003cdata.length; i++) {\\n var row = data[i];\\n var output = nn.forward(row.input);\\n var result = output.indexOf(Math.max(...output));\\n var isPass = row.target[result] == 1;\\n if(isPass) count++;\\n nn.backward(row.target, 0.01);\\n }\\n return count; \\n}\\n\\n// 執行測試資料\\nfunction test(data) {\\n \\n}\"}","created_at":"2024-03-05T09:49:27.350+08:00","updated_at":"2024-07-06T11:14:08.886+08:00","name":"AI 手寫辨識_正課_試玩版","language":"web","screenshot":{"url":"https://cdn4.koding.school/uploads/project/screenshot/706738/8bbe0d0cea215188852dbd12d59996c1.jpg"},"parent_id":697006,"plugin":"","description":null,"note":null,"status":"public","like_student_ids":[],"is_featured":false,"views":94,"hashid":"kdms8egmy","is_content_changed":false,"review_status":"unsubmitted","submitted_at":null,"reviewed_at":null,"advise":null,"is_deleted":false}
[{"id":15812098,"file_name":"mnist_fashion.jpg","project_id":706738,"asset_id":722016,"created_at":"2024-03-05T09:49:27.358+08:00","updated_at":"2024-03-05T09:49:27.358+08:00"},{"id":15812099,"file_name":"mnist.jpg","project_id":706738,"asset_id":722017,"created_at":"2024-03-05T09:49:27.360+08:00","updated_at":"2024-03-05T09:49:27.360+08:00"}]
橘蘋學習平台
橘蘋學習平台
我的作品
檢視專案頁
匯出
複製
匯入
刪除
下載 Android APP (APK)
截圖
前往網站頁面
1:1:1
1:1
full
用手機掃描下方 QRCode 進行安裝
或您也可以
下載 APK
到這台電腦
用手機掃描下方 QRCode 進行安裝
或您也可以
下載 APK
到這台電腦