【keras】应用实践(1) 线性回归

GitHub

https://github.com/calciferer/LearnKeras

简介

  • 通过一个简单的一元线性回归来学习Keras的使用
  • 需求:定义一个keras模型,让模型拟合这个回归方程
    y = 2 x + 1 y=2x+1 y=2x+1

直接使用python代码实现

1. 生成模拟数据

    def gen_data(self):
        """
        生成x,y数据。这里拟合一个线性函数 y = 2 * x + 1
        """
        # 生成训练集数据
        # x从0到10,生成101个
        x_train = np.linspace(0, 10, 101)
        y_train = x_train * 2 + 1
        self.x_train = x_train
        self.y_train = y_train
        return x_train, y_train
  • 数据集为:一共101个数
    – x:在这里插入图片描述
    – y:在这里插入图片描述
    – 这里x和y满足 y = 2 x + 1 y=2x+1 y=2x+1
    – 用图像表示
    在这里插入图片描述
    – 生成模拟数据的时候,也可以给每个y加上一点随机数,这样看起来更接近真实的情况。

2. 使用梯度下降开始训练

  • 定义要学习的函数 y ^ = W x + b \hat{y}=Wx+b y^=Wx+b ,只有W和b两个标量参数
  • 定义单个样本(x,y)的损失函数,这里采用MSE均方误差
    J ( W , b ) = ( y ^ − y ) 2 = ( W x + b − y ) 2 J(W,b)=(\hat{y}-y)^2=(Wx+b-y)^2 J(W,b)=(y^y)2=(Wx+by)2
  • J ( W , b ) J(W,b) J(W,b)分别对W和b求偏导数
    ∂ J ∂ W = 2 x ⋅ ( W x + b − y ) \frac{\partial{J}}{\partial{W}}=2x\cdot(Wx+b-y) WJ=2x(Wx+by)
    ∂ J ∂ b = 2 ⋅ ( W x + b − y ) \frac{\partial{J}}{\partial{b}}=2\cdot(Wx+b-y) bJ=2(Wx+by)
  • 更新参数公式(a是学习率)
    W = W − a ∂ J ∂ W W = W-a\frac{\partial{J}}{\partial{W}} W=WaWJ
    b = b − a ∂ J ∂ b b = b -a\frac{\partial{J}}{\partial{b}} b=babJ
  • 开始训练
def train(self):	
	alpha = 0.01 # 学习率
	epoch = 1 # 轮次
	# 初始化W,b
	W = 5.0
	b = 2.0
	for step in range(epoch):
	   print(f"开始第{step + 1}个epoch")
	   batch_size = 101 # batch大小
       W_grad_sum= 0.0  # 每个样本点对W偏导数的和
       b_grad_sum = 0.0  # 每个样本点对b偏导数的和
       total_loss = 0.0  # 总loss
       for index, (x, y) in enumerate(zip(self.x_train, self.y_train)):
           total_loss += (W * x + b - y) ** 2
           W_grad_sum += 2 * x * (W * x + b - y)
           b_grad_sum += 2 * (W * x + b - y)
           if (index + 1) % batch_size == 0 or index == len(self.x_train) - 1:
               print(f"经过第{int(index / batch_size) + 1}次迭代,当前index={index}")
               W -= alpha * (W_grad_sum / batch_size)  # 梯度和除以样本数
               b -= alpha * (b_grad_sum / batch_size)  # 梯度和除以样本数
               print(f'loss:{total_loss / batch_size},W={W},b={b}')
               W_grad_sum = 0.0
               b_grad_sum = 0.0
               total_loss = 0.0
	# 训练完成
	print(f"W:{W},b:{b}")
	# 获取模型的预测值
	y_pre = W * self.x_train + b
	
	# 绘制train散点图
	plt.plot(lr.x_train, lr.y_train, 'b.', markersize=1)
	plt.plot(lr.x_train, y_pre, 'r-')
	plt.show()
  • BatchSize的说明
    – 在这个例子中,样本大小为101:
    如果BatchSize设置为1,那么就属于SGD随机梯度下降,取得每个样本都进行一次梯度下降,更新一次W, b
    如果BatchSize设置为101,那么就属于BGD批量梯度下降,每个epoch只进行一次梯度下降
    如果BatchSize设置为1至101中的某个数,比如30,那么就属于MBGD(Mini-Batch)小批量梯度下降,每经过指定的batchSize,进行一次梯度下降,每遍历batchSize个样本,称为一次iteration(迭代)
  • 设置BatchSize=30,epoch=1的训练结果
    在这里插入图片描述
开始第1个epoch
经过第1次迭代,当前index=29
loss:35.365,W=4.7999,b=1.893
经过第2次迭代,当前index=59
loss:184.1637721688501,W=3.5695707699999994,b=1.6259489
经过第3次迭代,当前index=89
loss:153.60955990535018,W=1.710484948624333,b=1.37956387727
经过第4次迭代,当前index=100
loss:2.0640446086731177,W=1.8758650210476606,b=1.3969499574158581
W:1.8758650210476606,b:1.3969499574158581

使用Keras实现

  • 使用keras后,4行代码就搞定了
model = Sequential()
# 添加一个全连接层,units=1表示该层有一个神经元,input_dim=1表示x_train中每个样本的维度为1,初始值W=5,b=2
model.add(Dense(units=1, input_dim=1, kernel_initializer=Constant(5), bias_initializer=Constant(2)))
# 定义优化算法为sgd:随机梯度下降,定义损失函数为mse:均方误差
model.compile(optimizer=SGD(learning_rate=0.01), loss='mse')
model.fit(x_train, y_train, epochs=1, batch_size=30, shuffle=False)
  • 结果
    在这里插入图片描述
Epoch 1/1
batch:0,para:[array([[5.]], dtype=float32), array([2.], dtype=float32)]
30/101 [=======>......................] - ETA: 0s - loss: 35.3650
batch:1,para:[array([[4.7999]], dtype=float32), array([1.893], dtype=float32)]
batch:2,para:[array([[3.569571]], dtype=float32), array([1.6259489], dtype=float32)]
batch:3,para:[array([[1.7104847]], dtype=float32), array([1.3795638], dtype=float32)]
101/101 [==============================] - 0s 654us/step - loss: 111.4463
W:[[2.1615217]],b:[1.4269804]
  • 在batchSize=30时,结果不同的原因
    实际上,运行batch1,2,3后的结果是一样的,keras在运行3个batch后,最后一个batch的大小为101-30*3=11,小于30,因此最后这11个样本被忽略了。但一般来说训练会设置多个epoch,和多个iteration,并且注意到model.fit方法中有个shuffle参数(它表示每次iteration后是否混洗数据集,默认是True),这样每个样本基本上都会被训练到,忽略这些对结果影响不大。
  • 另外在进行随机梯度下降时,即BatchSize=1,epoch=1时得到的结果也有微小的差别
    python的结果:W:2.07600474478807,b:0.236057629049279
    keras的结果:W:[[2.0760052]],b:[0.23605807]
    这是因为keras的浮点数据类型为float32,python中默认为double
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值