TensorFlow.js - 使用 CNN(卷积神经网络) 识别手写数字

2023-11-19

目录

index.html

data.js

script.js

备注

参考文献


index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="Google Chrome">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>TensorFlow.js Tutorial</title>

  <!-- Import TensorFlow.js -->
  <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.0.0/dist/tf.min.js"></script>
  <!-- Import tfjs-vis -->
  <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-vis@1.0.2/dist/tfjs-vis.umd.min.js"></script>

  <!-- Import the data file -->
  <script src="data.js" type="module"></script>

  <!-- Import the main script file -->
  <script src="script.js" type="module"></script>

</head>

<body>
</body>
</html>


data.js

/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * =============================================================================
 */

 const IMAGE_SIZE = 784;
 const NUM_CLASSES = 10;
 const NUM_DATASET_ELEMENTS = 65000;
 
 const NUM_TRAIN_ELEMENTS = 55000;
 const NUM_TEST_ELEMENTS = NUM_DATASET_ELEMENTS - NUM_TRAIN_ELEMENTS;
 
 const MNIST_IMAGES_SPRITE_PATH =
     'https://storage.googleapis.com/learnjs-data/model-builder/mnist_images.png';
 const MNIST_LABELS_PATH =
     'https://storage.googleapis.com/learnjs-data/model-builder/mnist_labels_uint8';
 
 /**
  * A class that fetches the sprited MNIST dataset and returns shuffled batches.
  *
  * NOTE: This will get much easier. For now, we do data fetching and
  * manipulation manually.
  */
 export class MnistData {
   constructor() {
     this.shuffledTrainIndex = 0;
     this.shuffledTestIndex = 0;
   }
 
   async load() {
     // Make a request for the MNIST sprited image.
     const img = new Image();
     const canvas = document.createElement('canvas');
     const ctx = canvas.getContext('2d');
     const imgRequest = new Promise((resolve, reject) => {
       img.crossOrigin = '';
       img.onload = () => {
         img.width = img.naturalWidth;
         img.height = img.naturalHeight;
 
         const datasetBytesBuffer =
             new ArrayBuffer(NUM_DATASET_ELEMENTS * IMAGE_SIZE * 4);
 
         const chunkSize = 5000;
         canvas.width = img.width;
         canvas.height = chunkSize;
 
         for (let i = 0; i < NUM_DATASET_ELEMENTS / chunkSize; i++) {
           const datasetBytesView = new Float32Array(
               datasetBytesBuffer, i * IMAGE_SIZE * chunkSize * 4,
               IMAGE_SIZE * chunkSize);
           ctx.drawImage(
               img, 0, i * chunkSize, img.width, chunkSize, 0, 0, img.width,
               chunkSize);
 
           const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
 
           for (let j = 0; j < imageData.data.length / 4; j++) {
             // All channels hold an equal value since the image is grayscale, so
             // just read the red channel.
             datasetBytesView[j] = imageData.data[j * 4] / 255;
           }
         }
         this.datasetImages = new Float32Array(datasetBytesBuffer);
 
         resolve();
       };
       img.src = MNIST_IMAGES_SPRITE_PATH;
     });
 
     const labelsRequest = fetch(MNIST_LABELS_PATH);
     const [imgResponse, labelsResponse] =
         await Promise.all([imgRequest, labelsRequest]);
 
     this.datasetLabels = new Uint8Array(await labelsResponse.arrayBuffer());
 
     // Create shuffled indices into the train/test set for when we select a
     // random dataset element for training / validation.
     this.trainIndices = tf.util.createShuffledIndices(NUM_TRAIN_ELEMENTS);
     this.testIndices = tf.util.createShuffledIndices(NUM_TEST_ELEMENTS);
 
     // Slice the the images and labels into train and test sets.
     this.trainImages =
         this.datasetImages.slice(0, IMAGE_SIZE * NUM_TRAIN_ELEMENTS);
     this.testImages = this.datasetImages.slice(IMAGE_SIZE * NUM_TRAIN_ELEMENTS);
     this.trainLabels =
         this.datasetLabels.slice(0, NUM_CLASSES * NUM_TRAIN_ELEMENTS);
     this.testLabels =
         this.datasetLabels.slice(NUM_CLASSES * NUM_TRAIN_ELEMENTS);
   }
 
   // 从训练集返回随机批次的图片及其标签
   nextTrainBatch(batchSize) {
     return this.nextBatch(
         batchSize, [this.trainImages, this.trainLabels], () => {
           this.shuffledTrainIndex =
               (this.shuffledTrainIndex + 1) % this.trainIndices.length;
           return this.trainIndices[this.shuffledTrainIndex];
         });
   }
 
   // 从测试集中返回一批图片及其标签
   nextTestBatch(batchSize) {
     return this.nextBatch(batchSize, [this.testImages, this.testLabels], () => {
       this.shuffledTestIndex =
           (this.shuffledTestIndex + 1) % this.testIndices.length;
       return this.testIndices[this.shuffledTestIndex];
     });
   }
 
   nextBatch(batchSize, data, index) {
     const batchImagesArray = new Float32Array(batchSize * IMAGE_SIZE);
     const batchLabelsArray = new Uint8Array(batchSize * NUM_CLASSES);
 
     for (let i = 0; i < batchSize; i++) {
       const idx = index();
 
       const image =
           data[0].slice(idx * IMAGE_SIZE, idx * IMAGE_SIZE + IMAGE_SIZE);
       batchImagesArray.set(image, i * IMAGE_SIZE);
 
       const label =
           data[1].slice(idx * NUM_CLASSES, idx * NUM_CLASSES + NUM_CLASSES);
       batchLabelsArray.set(label, i * NUM_CLASSES);
     }
 
     const xs = tf.tensor2d(batchImagesArray, [batchSize, IMAGE_SIZE]);
     const labels = tf.tensor2d(batchLabelsArray, [batchSize, NUM_CLASSES]);
 
     return {xs, labels};
   }
 }


script.js

/*-------------------------------------------   进行设置   ----------------------------------------------------------------------*/

console.log('Hello TensorFlow');

/*-------------------------------------------   加载数据   ----------------------------------------------------------------------*/

// 导入数据
import {MnistData} from './data.js';

async function showExamples(data) {
  // 在 visor 中创建一个容器
  const surface =
    tfvis.visor().surface({ name: 'Input Data Examples', tab: 'Input Data'});

  // 获取示例
  const examples = data.nextTestBatch(20);
  const numExamples = examples.xs.shape[0];

  // 创建一个画布元素来呈现每个示例
  for (let i = 0; i < numExamples; i++) {
    const imageTensor = tf.tidy(() => {
      // 将图像重塑为 28x28 像素
      return examples.xs
        .slice([i, 0], [1, examples.xs.shape[1]])
        .reshape([28, 28, 1]);
    });

    // 为指定标签创建元素
    const canvas = document.createElement('canvas');
    canvas.width = 28;
    canvas.height = 28;
    canvas.style = 'margin: 4px;';
    await tf.browser.toPixels(imageTensor, canvas);
    surface.drawArea.appendChild(canvas);

    imageTensor.dispose();
  }
}

async function run() {
  const data = new MnistData();
  await data.load();
  await showExamples(data);

  const model = getModel();
  tfvis.show.modelSummary({name: 'Model Architecture', tab: 'Model'}, model);

  await train(model, data);

  await showAccuracy(model, data);
  await showConfusion(model, data);
}

document.addEventListener('DOMContentLoaded', run);

/*-------------------------------------------   定义模型架构   ----------------------------------------------------------------------*/

function getModel() {
  // 模型实例化
  const model = tf.sequential();

  // 各个维度的像素数量为 28 行和 28 列,深度为 1,因为我们的图片只有一个颜色通道
  const IMAGE_WIDTH = 28;
  const IMAGE_HEIGHT = 28;
  const IMAGE_CHANNELS = 1;

  model.add(tf.layers.conv2d({
    inputShape: [IMAGE_WIDTH, IMAGE_HEIGHT, IMAGE_CHANNELS],
    kernelSize: 5,      // 指定方形的 5x5 卷积窗口
    filters: 8,         // 对数据应用 8 个过滤器
    strides: 1,         // 指定步长为 1,表示过滤器将以 1 像素为步长在图片上滑动
    activation: 'relu', // 卷积完成后应用于数据的激活函数 (ReLU) 函数
    kernelInitializer: 'varianceScaling'  // 用于随机初始化模型权重的方法
  }));

  // MaxPooling 层用作在一个区域内最大值向下采样而不是平均。
  model.add(tf.layers.maxPooling2d({poolSize: [2, 2], strides: [2, 2]}));

  // 重复另一个 conv2d + maxPooling 堆栈。请注意,我们在卷积中有更多过滤器。
  model.add(tf.layers.conv2d({
    kernelSize: 5,
    filters: 16,
    strides: 1,
    activation: 'relu',
    kernelInitializer: 'varianceScaling'
  }));
  model.add(tf.layers.maxPooling2d({poolSize: [2, 2], strides: [2, 2]}));

  // 将其2-D输入展开为一个1-D长数组
  model.add(tf.layers.flatten());

  // 使用具有 softmax 激活的密集层计算 10 个可能的类的概率分布。得分最高的类将是预测的数字
  const NUM_OUTPUT_CLASSES = 10;
  model.add(tf.layers.dense({
    units: NUM_OUTPUT_CLASSES,
    kernelInitializer: 'varianceScaling',
    activation: 'softmax'
  }));

  // 选择优化器和损失函数
  const optimizer = tf.train.adam();
  model.compile({
    optimizer: optimizer,             // 选择优化器
    loss: 'categoricalCrossentropy',  // 当模型的输出为概率分布时,就会使用此函数
    metrics: ['accuracy'],            // 监控的另一个指标,是正确预测在所有预测中所占的百分比
  });

  return model;
}

/*-------------------------------------------   训练模型   ----------------------------------------------------------------------*/

async function train(model, data) {
  // 监控训练集的损失和准确率,以及验证集的损失和准确率
  const metrics = ['loss', 'val_loss', 'acc', 'val_acc'];
  const container = {
    name: 'Model Training', tab: 'Model', styles: { height: '1000px' }
  };
  const fitCallbacks = tfvis.show.fitCallbacks(container, metrics);

  const BATCH_SIZE = 512;
  const TRAIN_DATA_SIZE = 5500;
  const TEST_DATA_SIZE = 1000;

  // 训练模型的训练集
  const [trainXs, trainYs] = tf.tidy(() => {
    const d = data.nextTrainBatch(TRAIN_DATA_SIZE);
    return [
      d.xs.reshape([TRAIN_DATA_SIZE, 28, 28, 1]),
      d.labels
    ];
  });

  // 测试模型的验证集
  const [testXs, testYs] = tf.tidy(() => {
    const d = data.nextTestBatch(TEST_DATA_SIZE);
    return [
      d.xs.reshape([TEST_DATA_SIZE, 28, 28, 1]),
      d.labels
    ];
  });

  // 调用 model.fit 来启动训练循环
  return model.fit(trainXs, trainYs, {
    batchSize: BATCH_SIZE,
    validationData: [testXs, testYs],
    epochs: 10,
    shuffle: true,
    callbacks: fitCallbacks
  });
}

/*-------------------------------------------   评估模型   ----------------------------------------------------------------------*/

const classNames = ['Zero', 'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine'];

function doPrediction(model, data, testDataSize = 500) {
  const IMAGE_WIDTH = 28;
  const IMAGE_HEIGHT = 28;
  const testData = data.nextTestBatch(testDataSize);
  const testxs = testData.xs.reshape([testDataSize, IMAGE_WIDTH, IMAGE_HEIGHT, 1]);
  const labels = testData.labels.argMax(-1);      // argmax 函数为我们提供概率最高的类的索引
  const preds = model.predict(testxs).argMax(-1);

  testxs.dispose();
  return [preds, labels];
}

// 显示每个类的准确率
async function showAccuracy(model, data) {
  const [preds, labels] = doPrediction(model, data);
  const classAccuracy = await tfvis.metrics.perClassAccuracy(labels, preds);
  const container = {name: 'Accuracy', tab: 'Evaluation'};
  tfvis.show.perClassAccuracy(container, classAccuracy, classNames);

  labels.dispose();
}

// 显示混淆矩阵
async function showConfusion(model, data) {
  const [preds, labels] = doPrediction(model, data);
  const confusionMatrix = await tfvis.metrics.confusionMatrix(labels, preds);
  const container = {name: 'Confusion Matrix', tab: 'Evaluation'};
  tfvis.render.confusionMatrix(container, {values: confusionMatrix, tickLabels: classNames});

  labels.dispose();
}


备注

打开网页报错时,打开VS Code,在拓展处搜索“live server”插件,下载之后在.html文件右键后点击“open with live server”

 


参考文献

解决谷歌浏览器Failed to load resource: net::ERR_FAILED问题_illion booked-CSDN博客

https://codelabs.developers.google.com/codelabs/tfjs-training-classfication/index.html?hl=zh-CN#0

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TensorFlow.js - 使用 CNN(卷积神经网络) 识别手写数字 的相关文章

  • 将 OoXml 插入单词抛出错误:未知

    我一直在尝试通过office js将OOXML插入到word文档的正文内容中insertOoXML 方法 我什至尝试过最简单的实现 认为我在尝试替换 XML 本身中的 fieldCodes 时做了一些不正确的事情 所有结果都是这样Error
  • 如何在同一页面上使用AJAX处理多个表单

    我有一个表单 当我单击 提交 时 它就被提交了 然后该表单隐藏 操作页面的结果显示在 div 中 classname dig 它工作正常 但是当我添加另一个表单时 它停止正常工作并且所有表单同时提交 我如何更改我的代码 done click
  • 使用 vscode 调试器调试 next.js

    我已经使用安装了一个项目创建下一个应用程序 https github com segmentio create next app 我需要使用我的编辑器 vscode 调试服务器端渲染 所以我访问过vscode recipes 如何调试 ne
  • 了解设置 JQuery 变量

    了解设置 JQuery 变量 最近 我通过在 StackOverflow 上遇到的另一个问题寻找帮助 了解到如何设置 JQuery 变量 如下所示 您可以通过简单地调用变量来创建输入字段 并且锚变量似乎也定义了样式 var clicked
  • 如何恢复tensorflow inceptions检查点文件(ckpt)?

    I have inception resnet v2 2016 08 30 ckpt文件是预先训练的初始模型 我想使用恢复这个模型 saver restore sess ckpt filename 但为此 我将需要编写训练该模型时使用的变量
  • TypeError: props.render 不是一个函数(React hook 形式)

    我将方法作为我用react hook form制作的形式的道具传递 当从react hook form添加控制器时 它给了我 TypeError props render不是一个函数 我在网上找不到任何解决方案 因此感谢任何帮助 impor
  • 在 Vue.js 中从父组件执行子方法

    目前 我有一个 Vue js 组件 其中包含其他组件的列表 我知道使用 vue 的常见方式是将数据传递给孩子 并从孩子向父母发出事件 但是 在这种情况下 我想在子组件中的按钮出现时执行子组件中的方法 parent被点击 哪种方法最好 一种建
  • 使用 JavaScript 使链接保持活动状态并在单击时显示悬停效果

    I am struggling to make this work I d like to make it where if O F is clicked the hover state stays active if another li
  • Google App Engine:修改云运行环境

    我正在尝试部署一个使用自定义 Node js 服务器的 Next js 应用程序 我想将自定义构建变量注入应用程序 next config js const NODE ENV process env NODE ENV const envTy
  • 为什么是 javascript:history.go(-1);无法在移动设备上工作?

    首先 一些背景 我有一个向用户呈现搜索页面 html 表单 的应用程序 填写标准并单击 搜索 按钮后 结果将显示在标准部分下方 在结果列表中 您可以通过单击将您带到新页面的链接来查看单个结果的详细信息 在详细信息页面中 我添加了一个 返回结
  • Tensorboard SyntaxError:语法无效

    当我尝试制作张量板时 出现语法错误 尽管开源代码我还是无法理解 我尝试搜索张量板的代码 但不清楚 即使我不擅长Python 我这样写路径C Users jh902 Documents logs因为我正在使用 Windows 10 但我不确定
  • 使用 KnockoutJs 映射插件进行递归模板化

    我正在尝试使用以下方法在树上进行递归模板化ko映射 插入 http knockoutjs com documentation plugins mapping html 但我无法渲染它 除非我定义separate每个级别的模板 在以下情况下
  • 如何使输入字段和提交按钮变灰

    我想变灰这两件事 http doorsplit heroku com 歌曲输入字段和提交按钮 直到用户输入艺术家 有没有一种简单的方法可以通过 JQuery 来做到这一点 艺术家输入字段的id是 request artist 你可以这样做
  • Grails 在 javascript 内的 GSP 站点中使用 grails var

    我有一个在 GSP 文件中的 javascript 代码中使用 grails 变量值的问题 例如 我有一个会话值session getAttribute selectedValue 我想在 javascript 代码部分使用这个值 我现在的
  • Angular 2+ 安全性;保护服务器上的延迟加载模块

    我有一个 Angular 2 应用程序 用户可以在其中输入个人数据 该数据在应用程序的另一部分进行分析 该部分仅适用于具有特定权限的人员 问题是我们不想让未经授权的人知道how我们正在分析这些数据 因此 如果他们能够在应用程序中查看模板 那
  • 为什么在 Internet Explorer 中访问 localStorage 对象会引发错误?

    我正在解决一个客户端问题 Modernizr 意外地没有检测到对localStorageInternet Explorer 9 中的对象 我的页面正确使用 HTML 5 文档类型 并且开发人员工具报告该页面具有 IE9 的浏览器模式和 IE
  • Javascript转换时区问题

    我在转换当前时区的日期时间时遇到问题 我从服务器收到此日期字符串 格式为 2015 10 09T08 00 00 这是中部时间 但是当我使用 GMT 5 中的 new Date strDate 转换此日期时间时 它返回给我的信息如下 这是不
  • JQuery 图像上传不适用于未来的活动

    我希望我的用户可以通过帖子上传图像 因此 每个回复表单都有一个上传表单 用户可以通过单击上传按钮上传图像 然后单击提交来提交帖子 现在我的上传表单可以上传第一个回复的图像 但第二个回复的上传不起作用 我的提交过程 Ajax 在 php 提交
  • 将 MQTTNet 服务器与 MQTT.js 客户端结合使用

    我已经启动了一个 MQTT 服务器 就像this https github com chkr1011 MQTTnet tree master例子 该代码托管在 ASP Net Core 2 0 应用程序中 但我尝试过控制台应用程序 但没有成
  • 如何从图像输入中获取 xy 坐标?

    我有一个输入设置为图像类型

随机推荐

  • 统计学习方法论概念

    1 统计学习包含监督学习 非监督学习 半监督学习和强化学习 2 监督学习 监督学习的任务是学习一个模型 使模型能够根据任意给定的输入 对模型的输出做出一个好的预测 监督学习分为学习和预测两个过程 由学习系统和预测系统组成 3 损失函数和风险
  • 【C++】迭代器 && vector中迭代器失效

    文章目录 1 什么是迭代器 2 迭代器与指针 3 迭代器的分类 3 1具体分类 3 2为什么要对迭代器分类 3 3迭代器的使用建议 4 vector迭代器失效 4 1迭代器失效及其危害 4 2哪些操作会导致迭代器失效 如何解决 1 什么是迭
  • 视觉SLAM十四讲笔记-6-3

    视觉SLAM十四讲笔记 6 3 文章目录 视觉SLAM十四讲笔记 6 3 6 3 实践 曲线拟合问题 6 3 1 手写高斯牛顿法 6 3 2 使用Ceres进行曲线拟合 Ceres 简介 安装Ceres 使用Ceres拟合曲线 6 3 3
  • JAVA往map添加元素_java list map在初始化的时候添加元素

    List list new ArrayList add First Object add Second Object add Third Object Map map new HashMap put First Key First Valu
  • 初始OAuth2.0

    1 什么是OAuth2 0 OAuth2 0 是目前使用非常广泛的授权机制 用于授权第三方应用获取用户的数据 举例说明 用户可以通过选择其他登录方式来使用gitee 这里就使用到了第三方认证 OAuth 引入了一个授权层 用来分离两种不同的
  • vue 修改标题名字

    1 直接修改 在main js中添加 document title 大屏控制 2 根据路由动态改变 https www cnblogs com CinderellaStory p 10858035 html
  • iPhone苹果15手机怎么看是国行还是美版或港版的苹果iPhone15手机?

    iPhone苹果手机15机型区域版本识别代码 CH代码为国行 LL代码为美版 ZP代码为港版 iPhone苹果15手机怎么看是国行还是美版或港版的苹果iPhone15手机 1 打开苹果iPhone15手机桌面上的 设置 2 在iPhone苹
  • OWASP ZAP安装遇到Error.A JNI error has occurred ,please check your installation and try again

    问题描述 我当时下载的是兼容版本 下载完成后双击zap bat发现运行一下就闪退 然后运行jar文件就报错 过程 最开始以为是java环境的问题 后面用java version去运行了一下 发现java环境是正常的 但又一直提示java的问
  • 4大技术亮点支撑应用优势 全新一代旗舰型行业无人机千巡翼X4发布

    随着无人机与数字成像技术的发展 无人机航测成为了重要的地理信息采集手段 也越来越受重视 据相关研报数据统计 预计2025年我国实景三维在自然资源领域的 以数据采集 处理为主的直接市场规模预计将达40亿元 推测2025年关联市场规模将达400
  • MFC设置控件文本字体、大小、颜色、背景

    1 修改字体 大小 声明一个CFont类型的类成员变量 CFont m editFont 然后在类的初始化函数OnInitDialog 中添加以下两行代码 设置静态文本字体大小 m editFont CreatePointFont 180
  • MFC编程实验(三):组件(列表框元素的增删)

    一 实验要求 创建一个对话框应用程序 实现如下布局 完成如下功能 1 初始状态 列表中有4个元素 2 可以在编辑框中输入新朋友的名字 点击 添加 按钮添加到列表框 同时清空编辑框中的名字 3 选中列表框中的一个名字 点击 删除 按钮可以删除
  • GDB 简略手册

    杂项 命令 用法 说明 h elp help 显示可用帮助文档 h CMD 显示关于指定命令的帮助 apr opos apr REGEXP 使用正则表达式搜索命令 i nfo info 显示可展示的信息 ENTER 无命令回车 重复执行上一
  • 接口测试总结

    第一部分 主要从问题出发 引入接口测试的相关内容并与前端测试进行简单对比 总结两者之前的区别与联系 但该部分只交代了怎么做和如何做 并没有解释为什么要做 第二部分 主要介绍为什么要做接口测试 并简单总结接口持续集成和接口质量评估相关内容 第
  • 手写系列之--call/apply/bind/防抖/节流

    call call 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数 语法 function call thisArg arg1 arg2 JavaScript中由于函数的this指向它的直接调用者 我们变更调用者即
  • 1668 最大重复子字符串

    题目描述 给你一个字符串 sequence 如果字符串 word 连续重复 k 次形成的字符串是 sequence 的一个子字符串 那么单词 word 的 重复值为 k 单词 word 的 最大重复值 是单词 word 在 sequence
  • 第48讲 第49讲--动态定位单元格区域1-End属性、动态定位单元格区域2、3-Currentregion UsedRange

    1 单元格区域 EntireRow返回该区域所在的整行对象单元格区域 EntireColumn返回该区域所在的整列 返回单元格所在的整行与整列 返回单元格对象 EntireRow 与EntireColumn Sub 整行与整列 Range
  • 制作一个“生日快乐”App,来自程序员的生日礼物~

    点击上方 码农的后花园 选择 星标 公众号 精选文章 第一时间送达 之前给大家制作了一个来自程序员的表白神器 本期带大家做一个 生日快乐 App 来自程序员的生日礼物 不要再说程序员不懂浪漫咯 往期精彩 Android App 开发的三种姿
  • hibernate 异常

    1 异常 org hibernate AnnotationException No identifier specified for entity异常 entity类是必须要主键的 否则就会报出这个异常 Id GeneratedValue
  • 布隆过滤器的简单介绍与实例(Bloom Filter)

    转载https blog csdn net leeafay article details 78681534 布隆在1970年提出了布隆过滤器 Bloom Filter 是一个很长的二进制向量 可以想象成一个序列 和一系列随机映射函数 ha
  • TensorFlow.js - 使用 CNN(卷积神经网络) 识别手写数字

    目录 index html data js script js 备注 参考文献 index html