JavaScript 是一种流行的高级编程语言,它被世界上的绝大多数网站所使用,也被所有主流浏览器所支持。随着深度学习的火热,越来越多开发者开始探索使用 JavaScript 实现人工智能与机器学习算法。近日,来自德国的 Robin Wieruch 发布了一系列使用 JavaScript 构建机器学习的教程,本文将主要介绍使用 JavaScript 实现神经网络的方法。
JavaScript 是一种流行的高级编程语言,它被世界上的绝大多数网站所使用,也被所有主流浏览器所支持。随着深度学习的火热,越来越多开发者开始探索使用 JavaScript 实现人工智能与机器学习算法。近日,来自德国的 Robin Wieruch 发布了一系列使用 JavaScript 构建机器学习的教程,本文将主要介绍使用 JavaScript 实现神经网络的方法。
有网友对此表示:「我本想写一篇激烈的反驳文,其中阐述如果没有 GPU 的支持,这种做法是毫无意义的……但它可以使用 WebGL 来应用 GPU 的能力。而且,这可能比你在本地桌面上安装 TensorFlow 堆栈要简单一万倍。」
近期,原作者发表了一系列有关在 JavaScript 上实现人工智能和机器学习算法的文章,其中包括:
- 线性回归和梯度下降:https://www.robinwieruch.de/linear-regression-gradient-descent-javascript/
- 正规方程线性回归:https://www.robinwieruch.de/multivariate-linear-regression-normal-equation-javascript/
- 逻辑回归和梯度下降:https://www.robinwieruch.de/logistic-regression-gradient-descent-classification-javascript/
这些机器学习算法的实现是基于 math.js 库的线性代数(如矩阵运算)和微分的,你可以在 GitHub 上找到所有这些算法:
GitHub 链接:https://github.com/javascript-machine-learning
如果你发现其中存在任何缺陷,欢迎对这个资源提出自己的改进,以帮助后来者。我希望不断为 web 开发者们提供更多、更丰富的机器学习算法。
就我个人来说,我发现实现这些算法在某种程度上是一个非常具有挑战性的任务。特别是当你需要在 JavaScript 上实现神经网络的前向和反向传播的时候。由于我自己也在学习神经网络的知识,我开始寻找适用于这种工作的库。希望在不久的将来,我们能够轻松地在 GitHub 上找到相关的基础实现。然而现在,以我使用 JavaScript 的阅历,我选择了谷歌发布的 deeplearn.js 来进行此项工作。在本文中,我将分享使用 deeplearn.js 和 JavaScript 实现神经网络从而解决现实世界问题的方式——在 web 环境上。
首先,我强烈推荐读者先学习一下深度学习著名学者吴恩达的《机器学习》课程。本文不会详细解释机器学习算法,只会展示它在 JavaScript 上的用法。另一方面,该系列课程在算法的细节和解释上有着令人惊叹的高质量。在写这篇文章之前,我自己也学习了相关课程,并试图用 JavaScript 实现来内化课程中的相关知识。
神经网络的目的是什么?
本文实现的神经网络需要通过选择与背景颜色相关的适当字体颜色来改善网页可访问性。比如,深蓝色背景中的字体应该是白色,而浅黄色背景中的字体应该是黑色。你也许会想:首先你为什么需要一个神经网络来完成任务?通过编程的方式根据背景颜色计算可使用的字体颜色并不难,不是吗?我很快在 Stack Overflow 找到了该问题的解决办法,并根据我的需求做了调整,以适应 RGB 空间中的颜色。
function getAccessibleColor(rgb) { let [ r, g, b ] = rgb; let colors = [r / 255, g / 255, b / 255]; let c = colors.map((col) => { if (col <= 0.03928) { return col / 12.92; } returnMath.pow((col + 0.055) / 1.055, 2.4); }); let L = (0.2126 * c[0]) + (0.7152 * c[1]) + (0.0722 * c[2]); return (L > 0.179) ? [ 0, 0, 0 ] : [ 255, 255, 255 ]; }
当已经有一个编程的方法可以解决该问题的时候,使用神经网络对于该现实世界问题价值并不大,没有必要使用一个机器训练的算法。然而,由于可通过编程解决这一问题,所以验证神经网络的性能也变得很简单,这也许能够解决我们的问题。查看该 GitHub 库(https://github.com/javascript-machine-learning/color-accessibility-neural-network-deeplearnjs)中的动图,了解它最终表现如何,以及本教程中你将构建什么。如果你熟悉机器学习,也许你已经注意到这个任务是一个分类问题。算法应根据输入(背景颜色)决定二进制输出(字体颜色:白色或黑色)。在使用神经网络训练算法的过程中,最终会根据输入的背景颜色输出正确的字体颜色。
下文将从头开始指导你设置神经网络的所有部分,并由你决定把文件/文件夹设置中的部分合在一起。但是你可以整合以前引用的 GitHub 库以获取实现细节。
JavaScript 中的数据集生成
机器学习中的训练集由输入数据点和输出数据点(标签)组成。它被用来训练为训练集(例如测试集)之外的新输入数据点预测输出的算法。在训练阶段,由神经网络训练的算法调整其权重以预测输入数据点的给定标签。总之,已训练算法是一个以数据点作为输入并近似输出标签的函数。
该算法经过神经网络的训练后,可以为不属于训练集的新背景颜色输出字体颜色。因此,稍后你将使用测试集来验证训练算法的准确率。由于我们正在处理颜色,因此为神经网络生成输入颜色的样本数据集并不困难。
functiongenerateRandomRgbColors(m) { const rawInputs = []; for (let i = 0; i < m; i++) { rawInputs.push(generateRandomRgbColor()); } return rawInputs; } functiongenerateRandomRgbColor() { return [ randomIntFromInterval(0, 255), randomIntFromInterval(0, 255), randomIntFromInterval(0, 255), ]; } functionrandomIntFromInterval(min, max) { return Math.floor(Math.random() * (max - min + 1) + min); }
generateRandomRgbColors() 函数创建给定大小为 m 的部分数据集。数据集中的数据点是 RGB 颜色空间中的颜色。每种颜色在矩阵中被表征为一行,而每一列是颜色的特征。特征是 RGB 空间中的 R、G、B 编码值。数据集还没有任何标签,所以训练集并不完整,因为它只有输入值而没有输出值。
由于基于已知颜色生成可使用字体颜色的编程方法是已知的,因此可以使用调整后的功能版本以生成训练集(以及稍后的测试集)的标签。这些标签针对二分类问题进行了调整,并在 RGB 空间中隐含地反映了黑白的颜色。因此,对于黑色,标签是 [0,1];对于白色,标签是 [1,0]。
function getAccessibleColor(rgb) { let [ r, g, b ] = rgb; let color = [r / 255, g / 255, b / 255]; let c = color.map((col) => { if (col <= 0.03928) { return col / 12.92; } returnMath.pow((col + 0.055) / 1.055, 2.4); }); let L = (0.2126 * c[0]) + (0.7152 * c[1]) + (0.0722 * c[2]); return (L > 0.179) ? [ 0, 1 ] // black : [ 1, 0 ]; // white }
现在你已经准备好一切用于生成(背景)颜色的随机数据集(训练集、测试集),它被分类为黑色或白色(字体)颜色。
functiongenerateColorSet(m) { const rawInputs = generateRandomRgbColors(m); const rawTargets = rawInputs.map(getAccessibleColor); return { rawInputs, rawTargets }; }
使神经网络中底层算法更好的另一步操作是特征缩放。在特征缩放的简化版本中,你希望 RGB 通道的值在 0 和 1 之间。由于你知道最大值,因此可以简单地推导出每个颜色通道的归一化值。
functionnormalizeColor(rgb) { return rgb.map(v => v / 255); }
你可以把这个功能放在你的神经网络模型中,或者作为单独的效用函数。下一步我将把它放在神经网络模型中。
JavaScript 神经网络模型的设置阶段
现在你可以使用 JavaScript 实现一个神经网络了。在开始之前,你需要先安装 deeplearn.js 库:一个适合 JavaScript 神经网络的框架。官方宣传中说:「deeplearn.js 是一个开源库,将高效的机器学习构造块带到 web 中,允许在浏览器中训练神经网络或在推断模式下运行预训练模型。」本文,你将训练自己的模型,然后在推断模式中运行该模型。使用该库有两个主要优势:
- 首先,它使用本地电脑的 GPU 加速机器学习算法中的向量计算。这些机器学习计算与图解计算类似,因此使用 GPU 的计算比使用 CPU 更加高效。
- 其次,deeplearn.js 的结构与流行的 TensorFlow 库类似(TensorFlow 库也是谷歌开发的,不过它使用的是 Python 语言)。因此如果你想在使用 Python 的机器学习中实现飞跃,那么 deeplearn.js 可提供通向 JavaScript 各领域的捷径。
现在回到你的项目。如果你想用 npm 来设置,那么你只需要在命令行中安装 deeplearn.js。也可以查看 deeplearn.js 项目的官方安装说明文档。
npm install deeplearn
我没有构建过大量神经网络,因此我按照构建神经网络的一般实践进行操作。在 JavaScript 中,你可以使用 JavaScript ES6 class 来推进它。该类可以通过定义神经网络特性和类方法为你的神经网络提供完美的容器。例如,你的颜色归一化函数可以在类别中找到一个作为方法的点。
classColorAccessibilityModel{ normalizeColor(rgb) { return rgb.map(v => v / 255); } } export default ColorAccessibilityModel;
或许那也是你的函数生成数据集的地方。在我的案例中,我仅将类别归一化作为分类方法,让数据集生成独立于类别之外。你可以认为未来有不同的方法来生成数据集,不应该在神经网络模型中进行定义。不管怎样,这只是一个实现细节。
训练和推断阶段都在机器学习的涵盖性术语会话(session)之下。你可以在神经网络类别中设置会话。首先,你可以输入来自 deeplearn.js 的 NDArrayMathGPU 类别,帮助你以计算高效的方式在 GPU 上进行数学运算。
import { NDArrayMathGPU, } from 'deeplearn'; const math = new NDArrayMathGPU(); classColorAccessibilityModel{ ... } export default ColorAccessibilityModel;
第二,声明分类方法类设置会话。其函数签名使用训练集作为参数,成为从先前实现的函数中生成训练集的完美 consumer。第三步,会话初始化空的图。之后,图将反映神经网络的架构。你可以随意定义其特性。
import { Graph, NDArrayMathGPU, } from 'deeplearn'; classColorAccessibilityModel{ setupSession(trainingSet) { const graph = new Graph(); } .. } export default ColorAccessibilityModel;
第四步,你用张量的形式定义图中输入和输出数据点的形态。张量是具备不同维度的数组,它可以是向量、矩阵,或更高维度的矩阵。神经网络将这些张量作为输入和输出。在我们的案例中,有三个输入单元(每个颜色通道有一个输入单元)和两个输出单元(二分类,如黑白)。
classColorAccessibilityModel{ inputTensor; targetTensor; setupSession(trainingSet) { const graph = new Graph(); this.inputTensor = graph.placeholder('input RGB value', [3]); this.targetTensor = graph.placeholder('output classifier', [2]); } ... } export default ColorAccessibilityModel;
第五步,神经网络包含隐藏层。奇迹如何发生目前仍是黑箱。基本上,神经网络提出自己的交叉计算参数(在会话中经过训练)。不过,你可以随意定义隐藏层的维度(每个单元大小、层大小)。
classColorAccessibilityModel{ inputTensor; targetTensor; setupSession(trainingSet) { const graph = new Graph(); this.inputTensor = graph.placeholder('input RGB value', [3]); this.targetTensor = graph.placeholder('output classifier', [2]); let connectedLayer = this.createConnectedLayer(graph, this.inputTensor, 0, 64); connectedLayer = this.createConnectedLayer(graph, connectedLayer, 1, 32); connectedLayer = this.createConnectedLayer(graph, connectedLayer, 2, 16); } createConnectedLayer( graph, inputLayer, layerIndex, units, ) { ... } ... } export default ColorAccessibilityModel;
根据层的数量,你可以变更图来扩展出更多层。创建连接层的分类方法需要图、变异连接层(mutated connected layer)、新层的索引,以及单元数量。图的层属性可用于返回由名称确定的新张量。
classColorAccessibilityModel{ inputTensor; targetTensor; setupSession(trainingSet) { const graph = new Graph(); this.inputTensor = graph.placeholder('input RGB value', [3]); this.targetTensor = graph.placeholder('output classifier', [2]); let connectedLayer = this.createConnectedLayer(graph, this.inputTensor, 0, 64); connectedLayer = this.createConnectedLayer(graph, connectedLayer, 1, 32); connectedLayer = this.createConnectedLayer(graph, connectedLayer, 2, 16); } createConnectedLayer( graph, inputLayer, layerIndex, units, ) { return graph.layers.dense( `fully_connected_${layerIndex}`, inputLayer, units ); } ... } export default ColorAccessibilityModel;
神经网络中的每一个神经元必须具备一个定义好的激活函数。它可以是 logistic 激活函数。你或许已经从 logistic 回归中了解到它,它成为神经网络中的 logistic 单元。在我们的案例中,神经网络默认使用修正线性单元。
classColorAccessibilityModel{ inputTensor; targetTensor; setupSession(trainingSet) { const graph = new Graph(); this.inputTensor = graph.placeholder('input RGB value', [3]); this.targetTensor = graph.placeholder('output classifier', [2]); let connectedLayer = this.createConnectedLayer(graph, this.inputTensor, 0, 64); connectedLayer = this.createConnectedLayer(graph, connectedLayer, 1, 32); connectedLayer = this.createConnectedLayer(graph, connectedLayer, 2, 16); } createConnectedLayer( graph, inputLayer, layerIndex, units, activationFunction ) { return graph.layers.dense( `fully_connected_${layerIndex}`, inputLayer, units, activationFunction ? activationFunction : (x) => graph.relu(x) ); } ... } export default ColorAccessibilityModel;
第六步,创建输出二分类的层。它有两个输出单元,每一个表示一个离散的值(黑色、白色)。
classColorAccessibilityModel{ inputTensor; targetTensor; predictionTensor; setupSession(trainingSet) { const graph = new Graph(); this.inputTensor = graph.placeholder('input RGB value', [3]); this.targetTensor = graph.placeholder('output classifier', [2]); let connectedLayer = this.createConnectedLayer(graph, this.inputTensor, 0, 64); connectedLayer = this.createConnectedLayer(graph, connectedLayer, 1, 32); connectedLayer = this.createConnectedLayer(graph, connectedLayer, 2, 16); this.predictionTensor = this.createConnectedLayer(graph, connectedLayer, 3, 2); } ... } export default ColorAccessibilityModel;
第七步,声明一个代价张量(cost tensor),以定义损失函数。在这个案例中,代价张量是均方误差。它使用训练集的目标张量(标签)和训练算法得到的预测张量来计算代价。
classColorAccessibilityModel{ inputTensor; targetTensor; predictionTensor; costTensor; setupSession(trainingSet) { const graph = new Graph(); this.inputTensor = graph.placeholder('input RGB value', [3]); this.targetTensor = graph.placeholder('output classifier', [2]); let connectedLayer = this.createConnectedLayer(graph, this.inputTensor, 0, 64); connectedLayer = this.createConnectedLayer(graph, connectedLayer, 1, 32); connectedLayer = this.createConnectedLayer(graph, connectedLayer, 2, 16); this.predictionTensor = this.createConnectedLayer(graph, connectedLayer, 3, 2); this.costTensor = graph.meanSquaredCost(this.targetTensor, this.predictionTensor); } ... } export default ColorAccessibilityModel;
最后但并非不重要的一步,设置架构图的相关会话。之后,你就可以开始准备为训练阶段导入训练集了。
import { Graph, Session, NDArrayMathGPU, } from 'deeplearn'; classColorAccessibilityModel{ session; inputTensor; targetTensor; predictionTensor; costTensor; setupSession(trainingSet) { const graph = new Graph(); this.inputTensor = graph.placeholder('input RGB value', [3]); this.targetTensor = graph.placeholder('output classifier', [2]); let connectedLayer = this.createConnectedLayer(graph, this.inputTensor, 0, 64); connectedLayer = this.createConnectedLayer(graph, connectedLayer, 1, 32); connectedLayer = this.createConnectedLayer(graph, connectedLayer, 2, 16); this.predictionTensor = this.createConnectedLayer(graph, connectedLayer, 3, 2); this.costTensor = graph.meanSquaredCost(this.targetTensor, this.predictionTensor); this.session = new Session(graph, math); this.prepareTrainingSet(trainingSet); } prepareTrainingSet(trainingSet) { ... } ... } export default ColorAccessibilityModel;
不过目前在准备神经网络的训练集之前,设置还没完成。首先,你可以在 GPU 数学计算环境中使用回调函数(callback function)来支持计算,但这并不是强制性的,可自主选择。
import { Graph, Session, NDArrayMathGPU, } from 'deeplearn'; const math = new NDArrayMathGPU(); classColorAccessibilityModel{ session; inputTensor; targetTensor; predictionTensor; costTensor; ... prepareTrainingSet(trainingSet) { math.scope(() => { ... }); } ... } exportdefault ColorAccessibilityModel;
其次,你可以解构训练集的输入和输出(标签,也称为目标)以将其转换成神经网络可读的格式。deeplearn.js 的数学计算使用内置的 NDArrays。你可以把它们理解为数组矩阵中的简单数组或向量。此外,输入数组的颜色被归一化以提高神经网络的性能。
import { Array1D, Graph, Session, NDArrayMathGPU, } from 'deeplearn'; const math = new NDArrayMathGPU(); classColorAccessibilityModel{ session; inputTensor; targetTensor; predictionTensor; costTensor; ... prepareTrainingSet(trainingSet) { math.scope(() => { const { rawInputs, rawTargets } = trainingSet; const inputArray = rawInputs.map(v => Array1D.new(this.normalizeColor(v))); const targetArray = rawTargets.map(v => Array1D.new(v)); }); } ... } exportdefault ColorAccessibilityModel;
第三,shuffle 输入和目标阵列。shuffle 的时候,deeplearn.js 提供的 shuffler 将二者保存在 sync 中。每次训练迭代都会出现 shuffle,以馈送不同的输入作为神经网络的 batch。整个 shuffle 流程可以改善训练算法,因为它更可能通过避免过拟合来实现泛化。
import { Array1D, InCPUMemoryShuffledInputProviderBuilder, Graph, Session, NDArrayMathGPU, } from 'deeplearn'; const math = new NDArrayMathGPU(); classColorAccessibilityModel{ session; inputTensor; targetTensor; predictionTensor; costTensor; ... prepareTrainingSet(trainingSet) { math.scope(() => { const { rawInputs, rawTargets } = trainingSet; const inputArray = rawInputs.map(v => Array1D.new(this.normalizeColor(v))); const targetArray = rawTargets.map(v => Array1D.new(v)); const shuffledInputProviderBuilder = new InCPUMemoryShuffledInputProviderBuilder([ inputArray, targetArray ]); const [ inputProvider, targetProvider, ] = shuffledInputProviderBuilder.getInputProviders(); }); } ... } exportdefault ColorAccessibilityModel;
最后,馈送条目(feed entries)是训练阶段中神经网络前馈算法的最终输入。它匹配数据和张量(根据设置阶段的形态而定义)。
import { Array1D, InCPUMemoryShuffledInputProviderBuilder Graph, Session, NDArrayMathGPU, } from 'deeplearn'; const math = new NDArrayMathGPU(); classColorAccessibilityModel{ session; inputTensor; targetTensor; predictionTensor; costTensor; feedEntries; ... prepareTrainingSet(trainingSet) { math.scope(() => { const { rawInputs, rawTargets } = trainingSet; const inputArray = rawInputs.map(v => Array1D.new(this.normalizeColor(v))); const targetArray = rawTargets.map(v => Array1D.new(v)); const shuffledInputProviderBuilder = new InCPUMemoryShuffledInputProviderBuilder([ inputArray, targetArray ]); const [ inputProvider, targetProvider, ] = shuffledInputProviderBuilder.getInputProviders(); this.feedEntries = [ { tensor: this.inputTensor, data: inputProvider }, { tensor: this.targetTensor, data: targetProvider }, ]; }); } ... } exportdefault ColorAccessibilityModel;
这样,神经网络的设置就结束了。神经网络的所有层和单元都实现了,训练集也准备好进行训练了。现在只需要添加两个配置神经网络行为的超参数,它们适用于下个阶段:训练阶段。
import { Array1D, InCPUMemoryShuffledInputProviderBuilder, Graph, Session, SGDOptimizer, NDArrayMathGPU, } from 'deeplearn'; const math = new NDArrayMathGPU(); classColorAccessibilityModel{ session; optimizer; batchSize = 300; initialLearningRate = 0.06; inputTensor; targetTensor; predictionTensor; costTensor; feedEntries; constructor() { this.optimizer = new SGDOptimizer(this.initialLearningRate); } ... } export default ColorAccessibilityModel;
第一个参数是学习速率(learning rate)。学习速率决定算法的收敛速度,以最小化成本。我们应该假定它的数值很高,但实际上不能太高了。否则梯度下降就不会收敛,因为找不到局部最优值。
第二个参数是批尺寸(batch size)。它定义每个 epoch(迭代)里有多少个训练集的数据点通过神经网络。一个 epoch 等于一批数据点的一次正向传播和一次反向传播。以批次的方式训练神经网络有两个好处:第一,这样可以防止密集计算,因为算法训练时使用了内存中的少量数据点;第二,这样可以让神经网络更快地进行批处理,因为每个 epoch 中权重会随着每个批次的数据点进行调整——而不是等到整个数据集训练完之后再进行改动。
训练阶段
设置阶段结束后就到了训练阶段了。不需要太多实现,因为所有的基础都已在设置阶段完成。首先,训练阶段可以用分类方法来定义。然后在 deeplearn.js 的数学环境中再次执行。此外,它还使用神经网络实例所有的预定义特性来训练算法。
class ColorAccessibilityModel {
... train() { math.scope(() => { this.session.train( this.costTensor, this.feedEntries, this.batchSize, this.optimizer ); }); } } exportdefault ColorAccessibilityModel;
训练方法是 1 个 epoch 的神经网络训练。因此,从外部调用时,调用必须是迭代的。此外,训练只需要 1 个 epoch。为了多批次训练算法,你必须将该训练方法进行多次迭代运行。
这就是基础的训练阶段。但是根据时间调整学习率可以改善训练。学习率最初很高,但是当算法在每一步过程中逐渐收敛时,学习率会出现下降趋势。
classColorAccessibilityModel{ ... train(step) { let learningRate = this.initialLearningRate * Math.pow(0.90, Math.floor(step / 50)); this.optimizer.setLearningRate(learningRate); math.scope(() => { this.session.train( this.costTensor, this.feedEntries, this.batchSize, this.optimizer ); } } } exportdefault ColorAccessibilityModel;
在我们的情况中,学习率每 50 步下降 10%。下面,我们需要获取训练阶段的损失,来验证它是否随着时间下降。损失可在每一次迭代时返回,不过这样会导致较低的计算效率。神经网络每次请求返回损失,就必须通过 GPU 才能实现返回请求。因此,我们在多次迭代后仅要求返回一次损失来验证其是否下降。如果没有请求返回损失,则训练的损失下降常量被定义为 NONE(之前默认设置)
import { Array1D, InCPUMemoryShuffledInputProviderBuilder, Graph, Session, SGDOptimizer, NDArrayMathGPU, CostReduction, } from 'deeplearn'; classColorAccessibilityModel{ ... train(step, computeCost) { let learningRate = this.initialLearningRate * Math.pow(0.90, Math.floor(step / 50)); this.optimizer.setLearningRate(learningRate); let costValue; math.scope(() => { const cost = this.session.train( this.costTensor, this.feedEntries, this.batchSize, this.optimizer, computeCost ? CostReduction.MEAN : CostReduction.NONE, ); if (computeCost) { costValue = cost.get(); } }); return costValue; } } exportdefault ColorAccessibilityModel;
最后,这就是训练阶段。现在仅需要在训练集上进行会话设置后从外部进行迭代执行。外部的执行取决于训练方法是否返回损失。
推断阶段
最后一个阶段是推断阶段,该阶段使用测试集来验证训练算法的性能。输入是背景颜色中的 RGB 颜色,输出是算法为字体颜色是黑是白进行的 [ 0, 1 ] 或 [ 1, 0 ] 分类预测。由于输入数据点经过归一化,因此不要忘记在这一步也对颜色进行归一化。
classColorAccessibilityModel{ ... predict(rgb) { let classifier = []; math.scope(() => { const mapping = [{ tensor: this.inputTensor, data: Array1D.new(this.normalizeColor(rgb)), }]; classifier = this.session.eval(this.predictionTensor, mapping).getValues(); }); return [ ...classifier ]; } } exportdefault ColorAccessibilityModel;
该方法在数学环境中再次运行性能关键部分,需要定义一个映射,该映射最终可作为会话评估的输入。记住,预测方法不是一定得在训练阶段后运行。它可以在训练阶段中使用,来输出测试集的验证。至此,神经网络已经经历了设置、训练和推断阶段。
在 JavaScript 中可视化学习神经网络
现在是时候使用神经网络进行训练和验证/测试了。简单的过程为建立一个神经网络,使用一个训练集运行训练阶段,代价函数取得最小值之后,使用一个测试集进行预测。所有的过程只需要使用网页浏览器上的开发者控制台的几个 console.log statements 就可以完成。然而,由于该神经网络是关于颜色预测的,并且 deeplearn.js 是在浏览器上运行,从而可以轻松地对神经网络的训练阶段和测试阶段进行可视化。
至此,你可以自主决定你运行中的神经网
相关推荐
【项目资源】: 单片机项目适用于从基础到高级的各种项目,特别是在性能要求较高的场景中,比如操作系统开发、嵌入式编程和底层系统编程。如果您是初学者,可以从简单的控制台程序开始练习;如果是进阶开发者,可以尝试涉及硬件或网络的项目。 【项目质量】: 所有源码都经过严格测试,可以直接运行。 功能在确认正常工作后才上传。 【适用人群】: 适用于希望学习不同技术领域的小白或进阶学习者。 可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】: 项目具有较高的学习借鉴价值,也可直接拿来修改复刻。 对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】: 有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 鼓励下载和使用,并欢迎大家互相学习,共同进步。 # 注意 1. 本资源仅用于开源学习和技术交流。不可商用等,一切后果由使用者承担。 2. 部分字体以及插图等来自网络,若是侵权请联系删除。
毕设工坊:专注于计算机毕业设计项目的交流与资源共享平台,涵盖各类技术文档、代码示例及实战经验分享,助力学子顺利完成学业挑战。
【window 可视化nvm管理node版本 nvm-desktop】
资源内项目源码是来自个人的毕业设计,代码都测试ok,包含源码、数据集、可视化页面和部署说明,可产生核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果、标签分布图。都是运行成功后才上传资源,毕设答辩评审绝对信服的保底85分以上,放心下载使用,拿来就能用。包含源码、数据集、可视化页面和部署说明一站式服务,拿来就能用的绝对好资源!!! 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、大作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.txt文件,仅供学习参考, 切勿用于商业用途。
# 基于microbit编程语言的mymicrobit扩展插件项目 ## 项目简介 这是一个基于microbit编程语言的mymicrobit扩展插件项目。该项目旨在提供额外的功能和特性,以扩展microbit编程环境。通过此插件,用户可以轻松地在MakeCode环境中进行编程,实现对micro:bit设备的更多控制和功能实现。 ## 项目的主要特性和功能 1. 扩展性提供了丰富的积木块和代码库,允许用户轻松实现复杂的编程逻辑和功能扩展。 2. 图形化编程支持通过积木块形式的图形化编程,降低编程门槛,方便初学者快速上手。 3. 实时预览提供了积木块的实时预览功能,方便用户直观地了解代码块的逻辑和功能。 4. 与MakeCode无缝集成可以直接在MakeCode环境中导入和使用,无需额外的配置和安装。 ## 安装使用步骤
【项目资源】: 单片机项目适用于从基础到高级的各种项目,特别是在性能要求较高的场景中,比如操作系统开发、嵌入式编程和底层系统编程。如果您是初学者,可以从简单的控制台程序开始练习;如果是进阶开发者,可以尝试涉及硬件或网络的项目。 【项目质量】: 所有源码都经过严格测试,可以直接运行。 功能在确认正常工作后才上传。 【适用人群】: 适用于希望学习不同技术领域的小白或进阶学习者。 可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】: 项目具有较高的学习借鉴价值,也可直接拿来修改复刻。 对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】: 有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 鼓励下载和使用,并欢迎大家互相学习,共同进步。 # 注意 1. 本资源仅用于开源学习和技术交流。不可商用等,一切后果由使用者承担。 2. 部分字体以及插图等来自网络,若是侵权请联系删除。
资源内项目源码是来自个人的毕业设计,代码都测试ok,包含源码、数据集、可视化页面和部署说明,可产生核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果、标签分布图。都是运行成功后才上传资源,毕设答辩评审绝对信服的保底85分以上,放心下载使用,拿来就能用。包含源码、数据集、可视化页面和部署说明一站式服务,拿来就能用的绝对好资源!!! 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、大作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.txt文件,仅供学习参考, 切勿用于商业用途。
项目资源包含:可运行源码+sql文件 适用人群:学习不同技术领域的小白或进阶学习者;可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 项目具有较高的学习借鉴价值,也可拿来修改、二次开发。 有任何使用上的问题,欢迎随时与博主沟通,博主看到后会第一时间及时解答。 开发语言:Python 框架:django Python版本:python3.8 数据库:mysql 5.7 数据库工具:Navicat 开发软件:PyCharm 浏览器:谷歌浏览器
第三章-局域网-思维导图
内容概要:PT300机械故障综合模拟实验台由瓦仑尼安教学设备有限公司生产,旨在帮助用户深入了解振动特征知识及复杂转子振动频谱分析,实现精密振动分析和精准故障诊断。该实验台能模拟轴承故障、不平衡、不对中、设备松动、转子摩擦等多种机械故障现象,可进行不同转速下的轴承故障频率识别、转子静动平衡模拟试验、设备启停机测试等实验。设备采用高效节能ABB三相交流电动机,配备高精度转速控制和测量模块,确保运行稳定。此外,实验台还设有透明防震安全罩和互锁开关,保障实验安全。; 适合人群:高校师生、科研人员等需要学习或研究机械故障诊断相关理论知识和实践技能的人群。; 使用场景及目标:①用于高校等教育机构的教学,辅助学生理解机械故障诊断的理论知识和实践技能;②满足科研人员进行机械故障诊断算法验证、故障特征分析等科研需求。; 其他说明:PT300机械故障综合模拟实验台的每个部件均经过高精度加工,确保在不同振动状态下稳定运行。用户可根据期望分析特定部件的故障特征。设备尺寸为735mm(长)×310mm(宽)×350mm(高),保修一年,且提供免费操作指导服务。
【项目资源】: 适用于从基础到高级的各种项目,特别是在性能要求较高的场景中,比如操作系统开发、嵌入式编程和底层系统编程。如果您是初学者,可以从简单的控制台程序开始练习;如果是进阶开发者,可以尝试涉及硬件或网络的项目。 【项目质量】: 所有源码都经过严格测试,可以直接运行。 功能在确认正常工作后才上传。 【适用人群】: 适用于希望学习不同技术领域的小白或进阶学习者。 可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】: 项目具有较高的学习借鉴价值,也可直接拿来修改复刻。 对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】: 有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 鼓励下载和使用,并欢迎大家互相学习,共同进步。 # 注意 1. 本资源仅用于开源学习和技术交流。不可商用等,一切后果由使用者承担。 2. 部分字体以及插图等来自网络,若是侵权请联系删除。
内容概要:本文详细介绍了使用COMSOL Multiphysics的弱形式接口对三维光子晶体进行数值模拟的方法和技巧。文章通过具体的代码示例,解释了如何构建光子晶体的介电常数分布、设置弱形式PDE、处理电磁场切向连续性、应用Floquet周期边界条件以及特征值求解等关键步骤。特别强调了弱形式接口相比传统物理场接口的优势,如灵活性和对复杂边界的处理能力。文中还分享了一些实用的经验和注意事项,如布洛赫边界条件的实现、特征值求解器参数的优化配置以及网格划分的技巧。 适合人群:具备一定电磁学和数值模拟基础的研究人员或工程师,尤其是对光子晶体仿真感兴趣的读者。 使用场景及目标:①理解并掌握COMSOL弱形式接口在光子晶体仿真中的应用;②学习如何通过弱形式设置处理复杂的电磁场问题;③提高对光子晶体能带结构和带隙特性的认识;④掌握特征值求解和网格划分的最佳实践。 阅读建议:由于本文涉及较多的具体代码和物理概念,建议读者在阅读过程中结合COMSOL软件进行实际操作,同时查阅相关电磁理论书籍以加深理解。此外,对于文中提到的一些具体参数设置和技巧,可以通过尝试不同的配置来巩固所学知识。
# 基于Arduino平台的INSPTComputacion2项目 ## 项目简介 INSPTComputacion2是一个基于Arduino平台的开发项目。该项目旨在通过Arduino的硬件和软件能力,实现一系列计算和交互功能。通过此项目,用户可以体验到Arduino在嵌入式系统、物联网和微控制器等领域的强大功能。 ## 项目的主要特性和功能 该项目的主要特性和功能包括但不限于以下几点 1. 嵌入式系统开发利用Arduino的硬件资源,开发嵌入式系统应用。 2. 物联网应用实现Arduino与物联网技术的结合,进行数据采集、传输和控制。 3. 交互设计通过Arduino实现人机交互,如按钮控制、LED显示等。 4. 数据处理利用Arduino进行数据处理和分析,如温度、湿度等环境数据的采集和处理。 ## 安装使用步骤 以下是在已下载本项目源码文件后的安装使用步骤 1. 确保已安装Arduino IDE软件。
【项目资源】: 物联网项目适用于从基础到高级的各种项目,特别是在性能要求较高的场景中,比如操作系统开发、嵌入式编程和底层系统编程。如果您是初学者,可以从简单的控制台程序开始练习;如果是进阶开发者,可以尝试涉及硬件或网络的项目。 【项目质量】: 所有源码都经过严格测试,可以直接运行。 功能在确认正常工作后才上传。 【适用人群】: 适用于希望学习不同技术领域的小白或进阶学习者。 可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】: 项目具有较高的学习借鉴价值,也可直接拿来修改复刻。 对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】: 有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 鼓励下载和使用,并欢迎大家互相学习,共同进步。 # 注意 1. 本资源仅用于开源学习和技术交流。不可商用等,一切后果由使用者承担。 2. 部分字体以及插图等来自网络,若是侵权请联系删除。
【项目资源】: 物联网项目适用于从基础到高级的各种项目,特别是在性能要求较高的场景中,比如操作系统开发、嵌入式编程和底层系统编程。如果您是初学者,可以从简单的控制台程序开始练习;如果是进阶开发者,可以尝试涉及硬件或网络的项目。 【项目质量】: 所有源码都经过严格测试,可以直接运行。 功能在确认正常工作后才上传。 【适用人群】: 适用于希望学习不同技术领域的小白或进阶学习者。 可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】: 项目具有较高的学习借鉴价值,也可直接拿来修改复刻。 对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】: 有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 鼓励下载和使用,并欢迎大家互相学习,共同进步。 # 注意 1. 本资源仅用于开源学习和技术交流。不可商用等,一切后果由使用者承担。 2. 部分字体以及插图等来自网络,若是侵权请联系删除。
Python数据结构-学习笔记
该系统展示了一个电影在线购票系统的结构图,系统分为前台和后台两部分。前台包括首页、影院信息、电影信息、电影资讯和个人中心等模块,主要面向普通用户,提供电影浏览、选座购票、个人账户管理等功能。后台部分由管理员通过后台模块进行操作,包括系统首页、用户管理、场次管理、时间段管理、影院信息管理、电影分类管理、电影信息管理、订单管理和个人中心等模块,用于系统的维护和管理,如用户信息维护、电影和影院信息更新、订单处理等。整个系统旨在为用户提供便捷的在线购票体验,同时确保后台管理的高效和有序。
5G NR射频一致性自测用例 由于NR射频测试场景太多,全指标自动化跑测用时太久,本表格选取了主要场景的关键指标,以便于射频工程师对产品的NR射频指标进行初步摸底。 表格每一页概况: 1、NR TDD摸底指标N77/78/79/41 2、NR FDD摸底指标N1/3//5/8/28 附录1、各频段带宽所支持的SCS 附录2、各带宽SCS的RB配置 附录3、灵敏度测试的RB配置 附录4、摸底测试信道查询 附录5、各频段频率范围
【项目资源】: 物联网项目适用于从基础到高级的各种项目,特别是在性能要求较高的场景中,比如操作系统开发、嵌入式编程和底层系统编程。如果您是初学者,可以从简单的控制台程序开始练习;如果是进阶开发者,可以尝试涉及硬件或网络的项目。 【项目质量】: 所有源码都经过严格测试,可以直接运行。 功能在确认正常工作后才上传。 【适用人群】: 适用于希望学习不同技术领域的小白或进阶学习者。 可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】: 项目具有较高的学习借鉴价值,也可直接拿来修改复刻。 对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】: 有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 鼓励下载和使用,并欢迎大家互相学习,共同进步。 # 注意 1. 本资源仅用于开源学习和技术交流。不可商用等,一切后果由使用者承担。 2. 部分字体以及插图等来自网络,若是侵权请联系删除。
软件介绍: 一个永久免费且无广告的邮件群发软件,直接使用SMTP来群发邮件支持添加多个发信邮箱,一个小而美的邮件群发软件。 开发这个软件最初是打算用QQ获取某个群所有的群成员QQ,然后转换为QQ邮箱群发偷人的,结果现在发现QQ已经限制到只能是该群管理员、群主才可以获取群成员所有QQ了,所以获取群成员所有QQ邮箱的功能就没有上线了。 支持导入TXT文件一行一个邮箱、粘贴邮箱、查看邮箱列表、SMTP发信邮箱(支持多个)、管理SMTP邮箱、单个发信邮箱限制发送次数