4496|0

530

帖子

4

TA的资源

一粒金砂(高级)

楼主
 

《机器学习算法与实现 —— Python编程与应用实例》-- 第七贴 线性回归模型实战 [复制链接]

  

引言:

书中提到了很多机器学习算法与实现,从中选取了几个典型的算法,在PC上进行了实际体验。本书附带了丰富的电子资料,具体可参考:

链接已隐藏,如需查看请登录或者注册

本贴介绍的典型算法是线性模型,首先介绍书中介绍的一元一次线性拟合算法在pytorch的实现,然后介绍一元三次线性拟合算法的实现;本贴尝试了一元一次方程来拟合的实验过程,并在此基础上,尝试用一元二次方程来做拟合。通过使用一元二次线性函数来拟合,更进一步加深了机器学习的相关概念,目标函数,梯度,训练,极值。

 

环境说明:

 

硬件:

我做实验的环境是基于PC,内存

处理器   13th Gen Intel(R) Core(TM) i7-13700KF   3.40 GHz

机带 RAM     16.0 GB (15.7 GB 可用)

系统类型       64 位操作系统, 基于 x64 的处理器

GPU: RXT4060TI-8GB

软件:

Windows 11;

Pycharm社区版

Anaconda免费版

Torch

cuda

Git

pip

需要注意的是: 建议通过conda来管理python环境,在pycharm中,不同的工程可能需要安装不同的python库,这样管理起来比较方便。

另外,可以将conda/pip等资源的源更换为国内,清华源或者中科大源,否则由于墙的限制,下载一些python包的资源会非常慢。

本书也提到了具体的环境搭建方法,可参考:

链接已隐藏,如需查看请登录或者注册

 

 

一、一元一次线性算法的pytorch实现

1.1模型介绍

回顾文章中的一元一次线性模型:

 

最小二乘法来构造目标函数;

通过梯度下降法可以来找到这个误差函数的最小值,梯度在数学概念中就是导数,对于多元函数,需要求每个变量的偏导数;这个概念需要具备高等数学的知识,将一元一次函数的x和y,看成f(x,y), 分别求x和y的偏导数,则分别是它们的梯度函数;

 

梯度有什么意义呢?从几何意义来讲,一个点的梯度值是这个函数变化最快的地方。通俗上理解,我们初中/高中时学到加速度是速度的一阶导数,加速度越快,代表速度变化越快。梯度的含义也差不多。

 

针对一元线性回归问题,就是沿着梯度的反方向,不断改变 w 和 b 的值,最终找到一组最好的 w 和 b 使得误差最小

学习率:每次更新w/b的时候,需要决定更新的步长,这个就是学习率,用 η 表示。不同的学习率都会导致不同的结果,学习率太小会导致下降非常缓慢;学习率太大又会导致跳动非常明显。

 

按照含义, 每次w、b更新的公式就是:

w=w−η*∂f(w,b)/∂w

b=b−η*∂f(w,b)/∂b

 

1.2代码实现

import torch
import numpy as np

torch.manual_seed(2021)

# 生层测试数据
x_train = np.random.rand(20, 1)
y_train = x_train * 3 + 4 + 3*np.random.rand(20,1)

# 画出图像
import matplotlib.pyplot as plt

plt.plot(x_train, y_train, 'bo')
plt.show()

# 转换成 Tensor
x_train = torch.from_numpy(x_train)
y_train = torch.from_numpy(y_train)

# 定义参数 w 和 b
w = torch.randn(1, requires_grad=True) # 随机初始化
b = torch.zeros(1, requires_grad=True) # 使用 0 进行初始化

# 构建线性回归模型
def linear_model(x):
    return x * w + b

#def logistc_regression(x):
#    return torch.sigmoid(x*w+b)

y_ = linear_model(x_train)

plt.plot(x_train.data.numpy(), y_train.data.numpy(), 'bo', label='real')
plt.plot(x_train.data.numpy(), y_.data.numpy(), 'ro', label='estimated')
plt.legend()
plt.show()

# 计算误差
def get_loss(y_, y):
    return torch.sum((y_ - y) ** 2)

loss = get_loss(y_, y_train)
print(loss)

# 自动求导
loss.backward()

# 查看 w 和 b 的梯度
print(w.grad)
print(b.grad)

# 更新一次参数
w.data = w.data - 1e-2 * w.grad.data
b.data = b.data - 1e-2 * b.grad.data

y_ = linear_model(x_train)
plt.plot(x_train.data.numpy(), y_train.data.numpy(), 'bo', label='real')
plt.plot(x_train.data.numpy(), y_.data.numpy(), 'ro', label='estimated')
plt.legend()
plt.show()

for e in range(100):  # 进行 100 次更新
    y_ = linear_model(x_train)
    loss = get_loss(y_, y_train)

    w.grad.zero_()  # 注意:归零梯度
    b.grad.zero_()  # 注意:归零梯度
    loss.backward()

    w.data = w.data - 1e-2 * w.grad.data  # 更新 w
    b.data = b.data - 1e-2 * b.grad.data  # 更新 b
    if (e + 1) % 20 == 0:
        print('epoch: {}, loss: {}'.format(e, loss.item()))

y_ = linear_model(x_train)
plt.plot(x_train.data.numpy(), y_train.data.numpy(), 'bo', label='real')
plt.plot(x_train.data.numpy(), y_.data.numpy(), 'ro', label='estimated')
plt.legend()
plt.show()

 

1.3结果对比

待拟合数据:

 

第一次拟合后的对比:

 

中间拟合结果对比:

 

最终拟合结果:

 

 

 

 

二、一元二次方程拟合尝试

用f(x)=(x**2) * w0 + x * w1 + b来拟合,这里要注意,因为本实验中原始数据会变动,因此,每一次执行结果会变动,数据的不同,用一元二次和一元一次模型来拟合的精度可能也会有差别,这并不代表哪一个精度高,对比精度,应该用同样的数据来对比。这里就不做了,有兴趣的坛友,可以稍微改下程序,即可实现。

 

原理不多说直接上代码:

import torch
import numpy as np

torch.manual_seed(2021)

# 生层测试数据
x_train = np.random.rand(20, 1)
y_train = x_train * 3 + 4 + 3*np.random.rand(20,1)

# 画出图像
import matplotlib.pyplot as plt

plt.plot(x_train, y_train, 'bo')
plt.show()

# 转换成 Tensor
x_train = torch.from_numpy(x_train)
y_train = torch.from_numpy(y_train)

# 定义参数 w 和 b
w0 = torch.randn(1, requires_grad=True) # 随机初始化
w1 = torch.randn(1, requires_grad=True) # 随机初始化
b = torch.zeros(1, requires_grad=True) # 使用 0 进行初始化

# 构建线性回归模型
def linear_model(x):
    return (x**2) * w0 + x * w1 + b

#def logistc_regression(x):
#    return torch.sigmoid(x*w+b)

y_ = linear_model(x_train)

plt.plot(x_train.data.numpy(), y_train.data.numpy(), 'bo', label='real')
plt.plot(x_train.data.numpy(), y_.data.numpy(), 'ro', label='estimated')
plt.legend()
plt.show()

# 计算误差
def get_loss(y_, y):
    return torch.sum((y_ - y) ** 2)

loss = get_loss(y_, y_train)
print(loss)

# 自动求导
loss.backward()

# 查看 w 和 b 的梯度
print(w0.grad)
print(w1.grad)
print(b.grad)

# 更新一次参数
w0.data = w0.data - 1e-2 * w0.grad.data
w1.data = w1.data - 1e-2 * w1.grad.data
b.data = b.data - 1e-2 * b.grad.data

y_ = linear_model(x_train)
plt.plot(x_train.data.numpy(), y_train.data.numpy(), 'bo', label='real')
plt.plot(x_train.data.numpy(), y_.data.numpy(), 'ro', label='estimated')
plt.legend()
plt.show()

for e in range(100):  # 进行 100 次更新
    y_ = linear_model(x_train)
    loss = get_loss(y_, y_train)

    w0.grad.zero_()  # 注意:归零梯度
    w1.grad.zero_()  # 注意:归零梯度
    b.grad.zero_()  # 注意:归零梯度
    loss.backward()

    w0.data = w0.data - 1e-2 * w0.grad.data  # 更新 w
    w1.data = w1.data - 1e-2 * w1.grad.data  # 更新 w
    b.data = b.data - 1e-2 * b.grad.data  # 更新 b
    if (e + 1) % 20 == 0:
        print('epoch: {}, w0:{}, w1:{}, b:{}, loss: {}'.format(e, w0.data, w1.data, b.data, loss.item()))

y_ = linear_model(x_train)
plt.plot(x_train.data.numpy(), y_train.data.numpy(), 'bo', label='real')
plt.plot(x_train.data.numpy(), y_.data.numpy(), 'ro', label='estimated')
plt.legend()
plt.show()

原始数据:

 

结果:

 

 

 

点赞 关注

回复
举报
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表