深度学习(一)-线性回归

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/keyue123/article/details/89173561

  随着人工智能的发展,深度学习变得越来越炙手可热,所以博主也来凑一下热闹,抽空开始进行深度学习,下面是我自己 的一些学习经验分享,如果有错,请各位看官勿喷,帮忙指出一下,不胜感激。
  现在最热的深度学习框架为 T e n s o r F l o w TensorFlow P y t o r c h Pytorch 等等,下面我主要写的对象就为 P y t o r c h Pytorch ,内容参考的是廖星宇老师的《深度学习之pytorch》,我觉得这本书内容很基础,也很详细,非常适合初学者入门。 P y t o r c h Pytorch 基础部分网上有很多教程,我这里就不板门弄斧,后面我会再补上,这里就开始我们这章的主题:线性回归。

一维线性回归

1)原理

  线性回归大家应该都不陌生,简单说,就是给定一个数据集 D = { ( x i , y i ) } D=\{(x_i,y_i)\} ,线性回归希望可以找到一个最好的函数 f ( x ) f(x) ,使得 f ( x ) = w x + b f(x)=wx+b 能尽量多的拟合这些数据点。
我们一般使用向量的形式来表示函数 f ( x ) f(x)
f ( x ) = w T x + b {\text{f}}(x) = {w^T}x + b
  我们只需要通过不断的调整 w w b b ,就可以找到最符合条件的点。怎么学习这两个参数呢,其实只需要衡量 f ( x i ) f(x_i) y i y_i 之间的差别, 可以使用均方误差 L o s s = i = 1 m ( f ( x i ) y i ) 2 Loss = \sum\nolimits_{i = 1}^m {{{(f({x_i}) - {y_i})}^2}} 来衡量,要做的事情就是希望能够找到 w w b b ,使得:
( w , b ) = arg min w , b i = 1 m ( f ( x i ) y i ) 2 = arg min w , b i = 1 m ( y i w x i b ) 2 (w,b) = \mathop {\arg \min }\limits_{w,b} \sum\nolimits_{i = 1}^m {{{(f({x_i}) - {y_i})}^2}} = \mathop {\arg \min }\limits_{w,b} \sum\nolimits_{i = 1}^m {{{({y_i} - w{x_i} - b)}^2}}
  现在要求解这个连续函数的最小值,那么只需要求它的偏导数,让它的偏导数等于0来估计它的参数,即:
L o s s ( w , b ) w = 2 ( w i = 1 m x i 2 i = 1 m ( y i b ) x i ) = 0 \frac{{\partial Loss(w,b)}}{{\partial w}} = 2(w\sum\limits_{i = 1}^m {x_i^2 - } \sum\limits_{i = 1}^m {({y_i} - b){x_i}} ) = 0
L o s s ( w , b ) b = 2 ( m b i = 1 m ( y i w x i ) ) = 0 \frac{{\partial Loss(w,b)}}{{\partial b}} = 2(mb - \sum\limits_{i = 1}^m {({y_i} - w{x_i}} )) = 0

2)实现

  首先创建一些数据点:

	x_train = np.array([[3.3], [4.4], [5.5], [6.71], [6.93], [4.168],
	                    [9.779], [6.182], [7.59], [2.167], [7.042 ],
	                    [10.791], [5.313], [7.997], [3.1]], dtype=np.float32)
	
	y_train = np.array([[1.7], [2.76], [2.09], [3.19], [1.694], [1.573],
	                    [3.366], [2.596], [2.53], [1.221], [2.827], [3.465],
	                    [1.65], [2.904], [1.3]], dtype=np.float32)

  我们可以看看产生的这些离散的数据点:

	plt.scatter(x_train, y_train, color="r")
	plt.xlabel("X")
	plt.ylabel("Y")
	plt.show()

  有了数据,我们就可以开始创建模型:

	class LinearRegression(nn.Module):
	    def __init__(self):
	        super(LinearRegression, self).__init__()
	        self.linear = nn.Linear(1, 1)   # 输入和输出的维度都是1
	    
	    def forward(self, x):
	        out = self.linear(x)
	        return out

  上面我们定义了一个简单的模型 y = w x + b y=wx+b , 输入输出参数都是一维,当然这里可以根据我们想要的输入输出维度进行更改。同时可以根据电脑有没有英伟达的 G P U GPU ,来决定使用 C P U CPU 还是 G P U GPU 训练:

	if torch.cuda.is_available():
	    model = LinearRegression().cuda()
	else:
	    model = LinearRegression()

  模型创建好之后,我们需要定义优化函数和损失函数,在 p y t o r c h pytorch 中提供了 t o r c h . o p t i m torch.optim 方法优化我们的神经网络,我们可以直接使用,感兴趣的可以看看深度学习——优化器算法Optimizer详解

	criterion = nn.MSELoss()  # 损失函数
	optimizer = torch.optim.SGD(model.parameters(), 1e-3)	# 优化函数

  接下来我们就可以开始训练模型了,前面生成的数据为 numpy,需要将其转化为深度学习支持的 tensor:

	x_train = torch.from_numpy(x_train)    
	y_train = torch.from_numpy(y_train)

  模型训练,我们这里定义训练6000次:

	num_epochs = 6000
	for epoch in range(num_epochs):
	    x_train = Variable(x_train)   # 将数据变为 Variable
	    y_train = Variable(y_train)
	    
	    output = model(x_train)   # 训练模型
	    
	    loss = criterion(output, y_train)   # 计算损失
	
	    optimizer.zero_grad()   # 梯度归零,不然梯度会累加,造成无法收敛
	    loss.backward()   # 进行反向传播,计算损失函数对于网络参数的梯度值
	    optimizer.step()  # 更新参数值
	
	    if(epoch + 1) % 200 == 0:
	        print("loss: ", loss.data)

  每次训练后的损失如下:

	loss:  tensor(0.1865)
	loss:  tensor(0.1848)
	loss:  tensor(0.1833)
	loss:  tensor(0.1819)
	loss:  tensor(0.1806)
	loss:  tensor(0.1795)
	loss:  tensor(0.1784)
	loss:  tensor(0.1775)
	loss:  tensor(0.1767)
	loss:  tensor(0.1759)
	loss:  tensor(0.1752)
	loss:  tensor(0.1746)
	loss:  tensor(0.1741)
	loss:  tensor(0.1735)
	loss:  tensor(0.1731)
	loss:  tensor(0.1727)
	loss:  tensor(0.1723)
	loss:  tensor(0.1720)
	loss:  tensor(0.1717)
	loss:  tensor(0.1714)
	loss:  tensor(0.1712)
	loss:  tensor(0.1710)
	loss:  tensor(0.1708)
	loss:  tensor(0.1706)
	loss:  tensor(0.1704)
	loss:  tensor(0.1703)
	loss:  tensor(0.1701)
	loss:  tensor(0.1700)
	loss:  tensor(0.1699)
	loss:  tensor(0.1698)

  训练完成后,我们就得到了一条直线尽可能的靠近这些离散的点,下面可以看看预测的效果:

	plt.scatter(x_train.numpy(), y_train.numpy(), color="r", label="origin data")
	plt.plot(x_train.numpy(), output.data.numpy(), "b", label="predict data")
	plt.show()

多项式回归

  对于一般的线性回归,由于该函数拟合出来的是一条直线,所以精度欠佳,我们可以考虑多项式回归,也就是提高每个属性的次数,原理和上面的线性回归是一样的,只不过这里用的是高次多项式而不是简单的一次线性多项式 。
  首先给出我们想要拟合的方程:
y = 1 + 2 x + 3 x 2 + 4 x 3 y = 1 + 2x + 3{x^2} + 4{x^3}
  然后可以设置参数方程:
   y = b + w 1 x + w 2 x 2 + w 3 x 3 y = b + w_1x + w_2{x^2} + w_3{x^3}
  可以看到,上述方程与线性回归方程并没有本质区别。所以我们可以采用线性回归的方式来进行多项式的拟合,下面的代码实现,我就不一一细讲了。

	w_target = np.array([2, 3, 4]) # 定义参数
	b_target = np.array([1]) # 定义参数
	
	f_y = 'y = {:.2f} + {:.2f} * x + {:.2f} * x^2 + {:.2f} * x^3'.format(
	    b_target[0], w_target[0], w_target[1], w_target[2]) # 打印出函数的式子
	
	print(f_y)

  获得实际函数的方程式:
y = 1.00 + 2.00 x + 3.00 x 2 + 4.00 x 3 y = 1.00 + 2.00 * x + 3.00 * x^2 + 4.00 * x^3

	x_sample = np.arange(-1, 1.1, 0.1)
	y_sample = b_target[0] + w_target[0] * x_sample + w_target[1] * x_sample ** 2 + w_target[2] * x_sample ** 3
	
	plt.plot(x_sample, y_sample, label='real curve')
	plt.show()   # 实际图形

  数据准备,我们需要将数据处理成矩阵的方式:

	x_train = np.stack([x_sample ** i for i in range(1, 4)], axis=1)
	x_train = torch.from_numpy(x_train).float() # 转换成 float tensor
	
	y_train = torch.from_numpy(y_sample).float().unsqueeze(1) # 转化成 float tensor

  定义参数和模型,在这里模型也可以使用上面一维线性回归的模型创建方式,感兴趣的朋友可以自己尝试以下,我这里就不再次实现了。

	w = Variable(torch.randn(3, 1), requires_grad=True)
	b = Variable(torch.zeros(1), requires_grad=True)
	
	# 将 x 和 y 转换成 Variable
	x_train = Variable(x_train)
	y_train = Variable(y_train)
	
	def multi_linear(x):
	    return torch.mm(x, w) + b

  定义损失函数与优化函数

	criterion = nn.MSELoss()  # 损失函数
	optimizer = torch.optim.SGD([w, b], lr=1e-3)

  模型训练

	epoch = 0
	while True:
	    y_pred = multi_linear(x_train)
	    loss = criterion(y_pred, y_train)
	
	    optimizer.zero_grad()
	    loss.backward()
	    optimizer.step()
	
	    epoch += 1
	    if loss.data < 0.001:
	        print('epoch {}, Loss: {:.5f}'.format(epoch, loss.data))
	        break

  epoch 42571, Loss: 0.00100,可以看出最后训练了42571次,损失为1e-3,已经是很精确的,下面我们来看看实际效果:

	# 画出更新之后的结果
	y_pred = multi_linear(x_train)
	
	plt.plot(x_train.data.numpy()[:, 0], y_pred.data.numpy(), label='fitting curve', color='r')
	plt.plot(x_train.data.numpy()[:, 0], y_sample, label='real curve', color='b')
	plt.legend()

猜你喜欢

转载自blog.csdn.net/keyue123/article/details/89173561