我用JavaScript编写了一个梯度下降的线性回归模型,我几乎做到了,没有错误,但是有些错误,因为回归线不在正确的位置,并且一段时间之后线开始从这些观点走得更远 . 我正在使用安德鲁的Ng Coursera课程中的公式 . 我做错了什么?

这是我的代码:

var canvas = document.getElementById('canvas'),
	ctx = canvas.getContext('2d'),
	width = canvas.width = 650,
	height = canvas.height = 650,
	stop = false;

let data;

let graph;
let n;
let off;

let theta;
let X,Y;
let alpha;

let timer;

setup();
draw();

function setup(){
	console.clear();
	console.log('ready');

	data = [];
	graph = false;
	n = 11;
	off = Math.floor(width/n);
	
	theta = [0,1];
	X = [];
	Y = [];
	alpha = 0.01;

	timer = 0;
	
};

function draw(){
	ctx.clearRect(0,0,width,height);

	grid(n,n);

	for(let i = 0; i < data.length; i++){
		let pos = getCoor(data[i]);
		arc(pos.x,pos.y,2);
		if(graph){
			if(data[i+1] != undefined){
				let pos1 = getCoor(data[i+1]);
				line(pos.x,pos.y,pos1.x,pos1.y);
			}
		}
	}

	if(timer % 50 == 0 && timer > 0){
		//console.log(J(X,Y,theta));
		console.log(theta);
	}

	if(data.length > 1){
		theta = GradientDescend(X,Y,theta,alpha);
		regLine();
	}

	timer++;

	if(!stop){
		requestAnimationFrame(draw);
	};
};

if(stop){
	cancelAnimationFrame(draw);
};

function getCoor(data){
	let xx = data.x*width/n;
	let yy = height-data.y*height/n;

	return {x:xx,y:yy};
}

function regLine(){
	let m = theta[1];
	let b = theta[0];

	let x1 = 0;
	let y1 = height-m*x1+(b/11*width);
	let x2 = width;
	let y2 = height-m*x2+(b/11*width);

	line(x1,y1,x2,y2);
}

function grid(cx,cy){
	for(let d = 0; d < width; d+=off){
		ctx.lineWidth = 0.5;
		stroke(0);
		line(d,0,d,height);
		line(0,d,width,d);
	}
};

document.addEventListener("click",function(e){
	let xx = (e.clientX/width)*n;
	let yy = (1-e.clientY/height)*n;

	data.push({x:xx,y:yy});

	X.push([1,xx]);
	Y.push(yy);
});

document.addEventListener("dblclick",function(e){
	graph = !graph;
});

document.addEventListener("keydown",function(e){
	if(e.keyCode == 32){
		data = [];
		X = [];
		Y = [];
	}
})

function h(X,theta){
	let y = 0;
	for(let i = 0; i < theta.length; i++){
		y += theta[i]*X[i];
	}

	return y;
};

function J(X,Y,theta){
	let m = Y.length;
	let sum = 0;

	for(let i = 0; i < m; i++){
		let err = h(X[i],theta)-Y[i];
		sum += err*err;
	}

	return sum/m;
}

function GradientDescend(X,Y,theta,alpha){
	let m = Y.length;
	let thetaTT = theta;
	for(let i = 0; i < m; i++){
		for(let j = 0; j < thetaTT.length; j++){
			thetaTT[j] -= alpha*(1/m)*(h(X[i],thetaTT)-Y[i])*X[i][j];
		}
	}

	return thetaTT;
}

function arc(x, y, r,stroke){
	ctx.beginPath();
	ctx.arc(x, y, r, 0, Math.PI*2, false);
	if(stroke){
		ctx.stroke();
	}else{
		ctx.fill();
	}
}

function line(x, y, x1, y1){
	ctx.beginPath();
	ctx.moveTo(x, y);
	ctx.lineTo(x1, y1);
	ctx.stroke();
}

function stroke(r,g,b,a){
	if(typeof r === 'string'){
		ctx.strokeStyle = r;
	}
	if(!a){
		ctx.strokeStyle = 'rgb('+r+','+g+','+b+')';
	}
	if(arguments.length == 1){
		ctx.strokeStyle = 'rgb('+r+','+r+','+r+')';
	}
	if(arguments.length == 2){
		ctx.strokeStyle = 'rgba('+r+','+r+','+r+','+g+')';
	}else{
		ctx.strokeStyle = 'rgba('+r+','+g+','+b+','+a+')';
	}
}
#canvas {
	background-color: #cccccc;
	width: 650px;
	height: 650px;
	position: absolute;
	border: solid #999999 0.5px;
}
<canvas id="canvas"></canvas>