预测下载时间。
<!DOCTYPE html> <html> <head> <title>predict-download-time</title> <style> canvas { border: 1px solid #d3d3d3; } </style> <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script> </head> <body> </body> <script> window.onload = async function (){ const trainData = { sizeMB: [ 0.080, 9.000, 0.001, 0.100, 8.000, 5.000, 0.100, 6.000, 0.050, 0.500, 0.002, 2.000, 0.005, 10.00, 0.010, 7.000, 6.000, 5.000, 1.000, 1.000 ], timeSec: [ 0.135, 0.739, 0.067, 0.126, 0.646, 0.435, 0.069, 0.497, 0.068, 0.116, 0.070, 0.289, 0.076, 0.744, 0.083, 0.560, 0.480, 0.399, 0.153, 0.149 ] }; const testData = { sizeMB: [ 5.000, 0.200, 0.001, 9.000, 0.002, 0.020, 0.008, 4.000, 0.001, 1.000, 0.005, 0.080, 0.800, 0.200, 0.050, 7.000, 0.005, 0.002, 8.000, 0.008 ], timeSec: [ 0.425, 0.098, 0.052, 0.686, 0.066, 0.078, 0.070, 0.375, 0.058, 0.136, 0.052, 0.063, 0.183, 0.087, 0.066, 0.558, 0.066, 0.068, 0.610, 0.057 ] }; // 创建一个二维张量。第一个参数为张量的值,第二个参数为张量的形状即shape。 // 但这里的二维张量并不表示二维空间,而是指二秩张量或二轴张量。通常几维就等 // 于几轴、几秩序,有关术语如下: // // 形状:张量的每个轴的长度(元素数量)。 // 秩:张量的轴数。标量的秩为0,向量的秩为1,矩阵的秩为2。 // 轴或维度:张量的一个特殊维度。 // 大小:张量的总项数,即形状矢量元素的乘积。 // // 0维张量:标量(非数组) // 1维张量:矢量(一元数组) // 2维张量:矩阵(二元数组) // 3维张量:矩阵数组(rgb三通道就可以表示为这个) // 4维张量:矩阵数组的数组(从这里开始相当于从0维张量重新计算,但每个元素已经是是3维张量了) // 5维张量:矩阵数组的数组的数组 // ... // N维张量 const trainTensors = { sizeMB: tf.tensor2d(trainData.sizeMB, [20, 1]), // 输入数据,单特征。 timeSec: tf.tensor2d(trainData.timeSec, [20, 1]) // 标签。 }; // 创建测试用张量。 const testTensors = { sizeMB: tf.tensor2d(testData.sizeMB, [20, 1]), timeSec: tf.tensor2d(testData.timeSec, [20, 1]) }; // 除了通过上述传2个参数的方式创建张量,还可以直接传多维数组来创建张量,即只需要传一个参数 // 就行,比如: // tf.tensor2d([[1, 2], [3, 4]]); // 等同于: // tf.tensor2d([1, 2, 3, 4], [2, 2]); // 其中[2, 2]表示张量的形状,即有2个轴(数组元素个数),每个轴的元素数量为2。 // ***轴一般按照从全局到局部的顺序进行排序:首先是批次轴,随后是空间维度周周,最后是每个位 // 置的特征。这样,在内存中,特征向量就会位于连续的区域。 // 创建一个线性回归模型。 const model = tf.sequential(); // 给模型添加一个稠密层,我们在这里的输入期望为只有一个值的一维张量,操作方式也支持在上面的 // 创建模型的代码处以传参的方式添加。 // 对于线性回归模型的单层稠密层模型来说,kernel(内核、斜率)和bias(偏差)为可调的两个参数, // 下面内容会详细介绍。 // keras中的dense稠密层又称为full connected全连接的层。它表示每一个结点都与上一层的所 // 有结点相连,用来把前边提取到的特征综合起来。 // 层有关的配置都是针对keras的配置,要深入研究的话,可以查看keras和神经网络的教程。 // ***对于tfjs来说,它并没有像tf一样直接引用keras,而是实现了类似于keras的API,因此我们 // 也可以将其看为是引入了Keras,对于一些高级API的概念性理解上,可以这么认为。 model.add(tf.layers.dense({ inputShape: [1], // units代表该层的输出维度或神经元个数, units解释为神经元个数为了方便计算参数量,解释 // 为输出维度为了方便计算维度。 units: 1 })); // 配置模型训练选项。 model.compile({ // 优化器用于网络根据数据和损失函数更新其系数的算法。这里指定为随机梯度下降算法。 // ***梯度下降是深度学习背后的最基本的算法结构,其实现为反向传播。 optimizer: 'sgd', // 损失函数用于误差测量(平均绝对误差)。这是如何在训练数据上测量网络的性能。损失越少越好, // 当我们训练时,我们应该能够计算出随着时间的推移所造成的损失,并看到误差的下降。如果我们 // 的模型训练了很长一段时间,损失没有减少,这可能意味着我们的模型没有习得去拟合数据。 loss: 'meanAbsoluteError' }); // 对数据集以固定迭代数量的周期来训练模型,这一过程中,模型会对数据进行拟合。 await model.fit( trainTensors.sizeMB, // 输入。 trainTensors.timeSec, // 输出。 {epochs: 10} // 训练的迭代周期为10次。(先定为该值,后面会跟随注释的说明来更改) // {epochs: 200} // 训练的迭代周期为200次。 ); // 评估模型。evaluate与fit类似,区别在于评估模型不会去更新模型的系数,不会改变模型, // 评估就是计算平均损耗(误差),提供特征(输入)和目标数据(输出)来计算损耗,用于了解该模型在预测上的表现。 // meanAbsoluteError损耗函数,用于计算预测与目标之间的距离,取其绝对值(使它们全部为正), // 然后返回这些值的平均值。 model.evaluate(testTensors.sizeMB, testTensors.timeSec).print(); // epochs为10的时候,误差在0.7-2.8之间。 // 由于默认情况下模型是从随机初始状态训练而来的,梯度下降也将有随机性,因此每次执行将获得不同的值。 // 手动计算测试数据集的误差(平均绝对误差),得到与实际值相差多少的平均值,值约为0.22。 const avgDelaySec = tf.mean(trainData.timeSec); // 0.295。 tf.mean(tf.abs(tf.sub(testData.timeSec, avgDelaySec))).print(); // 0.2202250212430954。 // 从这个评估的输出我们可以发现,评估模型的输出结果很糟糕。而与评估值下面的我们手动计算的 // 误差来做对比,发现我们手动计算的误差其实更低。0.7-2.8之间,可是远大于0.22了。换句话说, // 这就意味着我们模型的准确性比我们手动计算的准确性还差。说明模型尚未学习到数据的真实结构, // 模型和数据并未充分拟合(欠拟合)。 // 稠密层模型在训练时,就是一个简单的线性方程:output = kernel * input + bias, // 在训练过程中output和input由我们提供的数据集来决定,相对来说是固定的。而kernel和bias // 参数则是在一开始被赋值为较小的随机值,我们称之为随机初始化。在训练过程中参数kernel和bias // 偏差值会逐步更新,也就是通过梯度下降的方式来进行优化。但太少的训练周期(epochs: 10)很 // 难使参数接近最佳值,因此我们继续加大训练迭代周期,解决欠拟合问题,然后再次评估修改迭代周 // 期后的模型。因此对调用fit方法的传入参数做以下修改,这也称之为调整超参数: // await model.fit( // ... // {epochs: 200} // 训练的迭代周期为200次。 // ); // 然后我们再通过评估模型得到的平均误差绝大多数时候都在0.055以内,这比我们手动计算的平均误差0.295 // 还要精确5倍以上。 // 从实际的梯度下降曲线(模型损耗随训练迭代周期变化)来看,当迭代周期从50起时,已基本处于良好拟合的位置。 // ***注意:模型的数据拟合程度不是越大越好,超过了合理的范围,可能会造成过度拟合(过拟合), // 相当于模型已经开始通过死记硬背的方式去学习训练数据,这样也会造成较大的误差。如何避免 // 过拟合和更隐蔽的过拟合是深度学习中一直需要面对的问题。 // 然后我们准备一组预测数据,来检验下我们的模型的真实效果。 // ***注意:这里需要将epochs重设为200. const smallFileMB = 1; const bigFileMB = 100; const hugeFileMB = 10000; const predictSizeMBTensor = tf.tensor2d([[smallFileMB], [bigFileMB], [hugeFileMB]]); model.predict(predictSizeMBTensor).print(); // 我们得到的预测结果如下(多次predict的结果也不是不同的,这里取平均的一个): // [[0.1342551], [6.4955053], [642.6205444]] // 1MB = > 0.1342551 // 100MB => 6.4955053 // 10000MB => 642.6205444 // 对于10000MB来讲,我们的训练数据中,没有任何接近此打下的示例,因此对该数据的预测是非常冒险的。 // 好了,这里总结一下,仅通过以下短短几行代码,我们就能进行训练、评估模型,也能通过模型做预测。 // 库和高级API的存在极大低降低了入门深度学习的难度。 // const model = tf.sequential([tf.layers.dense({inputShape: [1], units: 1})]); // model.compile({optimizer: 'sgd', loss: 'meanAbsoluteError'}); // (async () => await model.fit(trainTensors.sizeMB, trainTensors.timeSec, {epochs: 10}))(); // model.evaluate(testTensors.sizeMB, testTensors.timeSec); // model.predict(tf.tensor2d([[7.8]])).print(); }; </script> </html>
标签:const,示例,predict,模型,张量,js,timeSec,tf,model From: https://www.cnblogs.com/rock-roll/p/18203803