刚学完一部分就迫不及待来做练习看下自己的学习成果了,因为练习题目是英文的有些也看不太懂,所以有些理解错误的地方也请大家能够谅解拉。因此我也是一遍翻译一遍百度了一些资料才陆陆续续写完的,直接开始吧!
模型创建
我们直接推导一下“假设模型”,“代价模型”,“梯度下级模型”的公式吧,因为在后面的练习中牵涉“单变量的线性回归”以及“多变量的线性回归”都需要这三种模型,然后将这些推导公式转换为程序。在后面的题目中直接使用就可以了。
模型的数学推导
假设模型
具体模型如下图所示,其实就是特征矩阵X和向量θ之间的乘积,因为θ0部分的因变量是没有的,只是这边的X矩阵需要补1。
代价模型
下面是代价函数,这里最后可以变成X矩阵和向量θ的积的形式
梯度下降模型
下面是梯度下降模型,最后形式和代价函数差不多就是X特征矩阵和向量θ的积的形式
模型的程序实现
具体的推行推导完成后,就根据推导的模型以程序的方式进行呈现吧!
假设模型
参考上面的“假设模型”,其中feature就是传进来的特征值x0
x1
...xn
,然后再feature
矩阵的第一列中补1
,theta
就是θ
向量,feature
矩阵和theta
向量之间的乘积就是最终需要的值,这边也比较简单,具体代码如下
async Hypothesis(feature: tf.Tensor<tf.Rank>, theta: tf.Tensor<tf.Rank>) {
const ones = tf.ones([feature.shape[0], 1]);
const data = tf.concat([ones, feature], 1);
const hData = data.matMul(theta);
return hData.dataSync();
}
代价模型
参考上面的“代价模型”,因为推导过程中x0=1
,θn+1=-1
,因此需要在feature
矩阵中的第一列中补1
,在向量θ的最后补上-1
,然后将他们进行乘积所得到的值进行其他计算后得到具体的损失值。
async Cost(feature: tf.Tensor<tf.Rank>, theta: tf.Tensor<tf.Rank>) {
const one = tf.ones([feature.shape[0], 1]);
const X = tf.concat([one, feature], 1);
const ones = tf.fill([1, 1], -1);
const onesTheta = theta.concat(ones);
const sumData = X.matMul(onesTheta).pow(2).sum();
return sumData.div(2).div(feature.shape[0]).dataSync();
}
梯度下降模型
参考上面的“代价模型”,和上面一样的对feature
和theta
向量中补上1
和-1
后再进行乘积,在乘上当前θ
对应的xi
后进行其他的四则运算就可以算出下降后的当前θ
的值。
async Gradient(
feature: tf.Tensor<tf.Rank>,
theta: tf.Tensor<tf.Rank>,
alpha: number
) {
const one = tf.ones([feature.shape[0], 1]);
const featureData = tf.concat([one, feature], 1);
const ones = tf.fill([1, 1], -1);
const onesTheta = theta.concat(ones);
const X = featureData.slice([0, 0],[featureData.shape[0], (featureData.shape[1] || 1) - 1]);
const sumValue = featureData.matMul(onesTheta).mul(X).sum(0, true).transpose();const data = theta.sub(sumValue.mul(alpha).div(featureData.shape[0]));
return data;
}
梯度下降算法
其中alpha(学习速率α),theta(初始的θ),下降次数从外面传入,返回最终下降后的θ向量。
async GradientDescent(
feature: tf.Tensor<tf.Rank>,
alpha: number,
theta: tf.Tensor<tf.Rank>,
iterations: number
) {
let i = 0;
for (let i = 0; i < iterations; i++) {
theta = await this.Gradient(feature, theta, alpha);
}
return theta;
}
}
我们现在已经完成了上面所有模型的实现程序,准备工作都已经最好了,后面就开始做习题吧!
单变量线性回归
题目的大概意思就是,如果你是管理了一家餐饮公司,并且给你一簇城市人口和盈利的数据对比,让你推导人口和盈利的关系。
读取数据
第一步肯定是读取数据了,我们直接用一开始就写好的方法来读取数据就可以了。
const data = ReadData("./data/ex1data/ex1data1.txt");
ctx.body = data;
画点阵图
画点阵图就是将数据读出来后,通过我们事先封装的方法画出来就可以了。
var myCharts = new MyCharts('scatterContainer', 0, 30, -6, 30);
myCharts.writeScatter(data1);
最终画出来的图是这样子的
推导θ0=0,θ1=0时代价函数的值
使用“代价模型”程序就可以了,传入θ
向量为[[0],[0]]
,特征矩阵也就是我们拿到的数据部分,将它们传入到已经写好的到“代价模型”方法中就可以了,最终得到的值为32.07273483276367
,与练习中给出的一致。
async data1_showCost(ctx: Context) {
const _ex1Service = new ex1Service();
const data = ReadData("./data/ex1data/ex1data1.txt");
const feature = tf.tensor(data);
const initTheta = tf.tensor([[0], [0]]);
const cost = await _ex1Service.Cost(feature, initTheta);
ctx.body = cost;
}
画出假设函数
直接调用“梯度下降算法”,传入拿到的数据和θ
,α
为0.01
,得到最终下降后的θ矩阵。
async data1_showScatterAndLine(ctx: Context) {
const _ex1Service = new ex1Service();
const data = ReadData("./data/ex1data/ex1data1.txt");
let feature = tf.tensor(data);
let thInit = tf.tensor([[0], [0]]);
let theta =await _ex1Service.GradientDescent(feature, 0.01, thInit, 1000);
ctx.body = theta.dataSync();
}
具体划线就补贴代码了,最终画出来的图是这样子的
画学习速率曲线
学习速率曲线就是下降次数和损失值之间的关系,我们只需要在下降循环中调用一遍代价函数算损失值就可以了,按照这个思路写一个学习速率曲线的函数。
async LearningCurve(
feature: tf.Tensor<tf.Rank>,
alpha: number,
theta: tf.Tensor<tf.Rank>,
iterations: number
) {
const elearningData: Array<any> = [];
let i = 0;
for (let i = 0; i < iterations; i++) {
elearningData.push({ x: i, value: (await this.Cost(feature, theta))[0] });
theta = await this.Gradient(feature, theta, alpha);
}
return elearningData;
}
接下去直接调用学习速率曲线的函数轻松拿到下降次数和损失值的关系
async data1_showLearningCurve(ctx: Context) {
const _ex1Service = new ex1Service();
const data = ReadData("./data/ex1data/ex1data1.txt");
let feature = tf.tensor(data);
let thInit = tf.tensor([[0], [0]]);
let curveValue =await _ex1Service.LearningCurve(feature, 0.01, thInit, 1000);
console.log(curveValue)
ctx.body = curveValue;
}
具体前端划线就不贴代码了,最终画出来是这样子的
到这里的时候单变量的所有了联系都已经完成了,接下去一口气把多变量的线性回归联系也一起完成吧!
多变量线性回归
这题给出了房价与面积和房间数量的对应数据,需要我们画出不同学习速度α下面的学习速率,有了前面已经写好的模型方法就很简单了,我们直接开干!
读取数据
const data = ReadData("./data/ex2data/ex2data1.txt");
画学习速率曲线
直接通过前面写完的学习速率曲线函数画出不同α下的曲线就可以了
我们这边的α直接取[0.001, 0.003, 0.1, 0.3]
四个值
let alpha = [0.001, 0.003, 0.1, 0.3]
另外针对feature特征值也需要进行归一化
feature = feature.sub(feature.mean(0,true)).div(tf.moments(feature,0,true).variance.sqrt());
最后循环不同的学习速度,并调用学习速率曲线函数,拿到不同学习速度下面的曲线,完整代码如下
async data2_showLearningCurveByEveryAlpha(ctx: Context) {
const _ex1Service = new ex1Service();
const data = ReadData("./data/ex2data/ex2data1.txt");
let alpha = [0.001, 0.003, 0.1, 0.3];
let thInit = tf.tensor([[0], [0], [0]]);
let feature = tf.tensor(data);
feature = feature
.sub(feature.mean(0, true))
.div(tf.moments(feature, 0, true).variance.sqrt());
let curveValue: Array<any> = [];
for (let i = 0; i < alpha.length; i++) {
curveValue.push(
await _ex1Service.LearningCurve(feature, alpha[i], thInit, 2000)
);
}
ctx.body = curveValue;
}
具体前端画图就补贴代码了,下面就是我们最终画出来的图
代码下载
将代码上传到了GitHub,想要的小伙伴直接下载吧 点击进入