深度学习代码笔记1 第一讲:线性问题

自序

        这是我注册CSDN以来的第一个系列笔记,我小时候就没有记笔记的习惯,现在越来越觉得整理和记录是一件重要的事。我将在这个系列陆续记录一些深度学习的入门系列代码,一方面是做些记录,另一方面是做个见证。未来,我计划写更深入和系统性的代码知识,数学知识、力学知识。

代码笔记1的说明

        第一个系列我选择更新的是b站用户"刘二大人"制作的 基于Pytorch的深度学习实践 课程配套的代码,本系列所有的代码均由我自行编译测试过,其中有一些内容是自己补充进去的,我想通过互联网和大家一起交流,欢迎大家批评指正。为了便于记录,笔记中会放一些刘老师的PPT截图。

第一讲:线性问题

1.课程代码

2.课后习题

3.三维绘图

问题描述:这一讲的目标是训练一个线性模型拟合如下任务,在本次训练中不涉及梯度更新等深度学习原理,而是通过某种穷举手段简要了解深度学习是做什么的。

深度学习的核心步骤:数据集、模型、训练和推理。

第一讲的数据集就是两列散点,模型是线性模型,训练是手动寻优,而推理是第四个点的函数值,或者说是一个简单的回归问题。

这段代码定义了forward函数和损失模型,是均方误差损失的手动实现(还没有除以数据个数)。我在测试代码时发现加法的机器误差会影响初学者对模型的理解,选择使用round()函数强制将计算结果保留了两位。

import numpy as np
import matplotlib.pyplot as plt

def forward(x, w):
    y_hat = x * w
    y_hat = round(y_hat, 2)
    return y_hat

def loss(x, y, w):
    y_hat = forward(x, w)
    return (y_hat - y) * (y_hat - y)

#最好要用少用全局变量的习惯,所以该传的参数不要省略

这段代码给出了训练集(这少得可怜的数据集就别拆分了),在for训练循环前,给了几个空列表和epoch训练轮次初始值,这是经典的存储办法了,并且也是为后面可视化提供绘图数据。在for循环中,其实forward不写也行,这里是为了输出一下。首先完成loss值的计算,然后打印输出数据集、预测值和损失值,最后对每一小循环的损失值除以数据点个数实现平均化。这个过程中并没有“学习”,而是在展示手动改变参数后模型的差异。最后需要注意,每次小循环会算三个loss,分别代表三个散点的拟合损失结果,最后哥仨加起来取均值才表示这一次训练的损失。

所谓深度学习的学习,是指模型在自动更新参数,自动收敛到最优参数,这些最优参数就组成了拟合出来的模型。 

x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0 ,6.0]

w_list = []
mse_list = []
epochs = []
epoch = 1
for w in np.arange(0.0, 4.1, 0.1):
    epochs.append(epoch)
    epoch += 1
    print('w =', round(w, 2))
    l_sum = 0
    for x_val, y_val in zip(x_data, y_data):
        y_hat_val = forward(x_val, w)
        loss_val = loss(x_val, y_val, w)
        l_sum += loss_val
        y_hat_val = round(y_hat_val, 2)
        loss_val = round(loss_val, 2)
        l_sum = round(l_sum, 2)
        print('\t', x_val, y_val, y_hat_val, loss_val)
    print('MSE =', l_sum / 3)
    w_list.append(w)
    mse_list.append(l_sum / 3)

这个可视化分别表达了loss对于这一讲唯一“可学习”的参数w和训练轮次epoch的变化情况,其中后者是写论文经常要给出来的图。 

plt.plot(w_list, mse_list)
plt.ylabel('Loss')
plt.xlabel('w')
plt.title('Loss over w')
plt.show()

plt.plot(epochs, mse_list)
plt.ylabel('Loss')
plt.xlabel('Epochs')
plt.title('Loss over Epochs')
plt.show()

可视化的结果:w=2的时候Loss=0,也就是炼丹师傅们梦寐以求的那种模型了嘿嘿:

y=2x

 线性问题课后习题解答

习题大概是说,增加一个可学习参数,模型的表达能力会不会更好。从理论上说,维度更高、耦合信息更多的空间能学到更复杂的模型,当假设空间维度不那么高,用一个过于复杂的模型来做训练,效果可能不会很好。落到这个课后习题上则不会有什么问题,它的模式可以肉眼看出来。

 我们选择一个目标线性模型,也即,对于训练出的模型,最理想的状态就是和它一模一样:

y=8x+17

我选了如图所示的四个散点作为”Dataset“:[1.0, 2.0, 3.0, 4.0]; [25.0, 33.0, 41.0, 49.0].

注意到,对于y=wx+b,模型中出现了第二个可学习参数(截距b),以后可以知道它学名叫bias。编程求解的基本逻辑是:手动遍历w的同时,也要遍历截距b,w和b的组合就是学习到的模型

参考答案如下:

import numpy as np
import matplotlib.pyplot as plt


x_data = [1.0, 2.0, 3.0, 4.0]
y_data = [25.0, 33.0, 41.0, 49.0]


def forward(x, w, b):
    return x * w + b


def loss(y_pred, y_true):
    return (y_pred - y_true) ** 2


w_range = np.arange(0.0, 20.0, 0.1)
b_range = np.arange(10.0, 30.0, 0.1)

W, B = np.meshgrid(w_range, b_range) #生成3D网格点坐标矩阵,这里的输入就是网格点的横纵坐标列向量,而输出就是坐标矩阵
MSE = np.zeros_like(W)

loss_list = []

for i in range(len(w_range)):
    for j in range(len(b_range)):
        w = w_range[i]
        b = b_range[j]
        mse_sum = 0
        for x_val, y_val in zip(x_data, y_data):
            y_pred = forward(x_val, w, b)
            mse_sum += loss(y_pred, y_val)
        MSE[j, i] = mse_sum / len(x_data)
        loss_list.append(mse_sum / len(x_data))

#三维图
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(W, B, MSE, cmap='coolwarm')
ax.set_xlabel('w')
ax.set_ylabel('b')
ax.set_zlabel('MSE')
plt.show()
"""
cmap='plasma': 紫红色调的颜色映射。
cmap='inferno': 黄红色调的颜色映射。
cmap='magma': 黑紫色调的颜色映射。
cmap='cividis': 暖色调的颜色映射。
cmap='coolwarm': 冷暖色调的颜色映射。"""

# 画一下loss关于epochs的图,每隔一定的步长绘制一个数据点
step_size = 400
plt.plot(np.arange(0, len(loss_list), step_size), loss_list[::step_size])
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Loss over Epochs')
plt.show()

# 输出一下最终得到的参数和最优loss
min_loss_index = np.unravel_index(np.argmin(MSE), MSE.shape)
best_w = w_range[min_loss_index[1]] #注意这是列
best_b = b_range[min_loss_index[0]]

print(f"Best w: {best_w:.2f}, Best b: {best_b:.2f}")
print(np.min(MSE))

我们选择输出了一下参数和最优loss:

Best w: 8.00, Best b: 17.00
7.604619126330554e-28

三维绘图

在本小节的最后我附上官方示例中两段三维绘图的代码,有助于大家熟悉习题中三维绘图的范式。

import matplotlib.pyplot as plt
import numpy as np
#
# Fixing random state for reproducibility
np.random.seed(19680801)


def randrange(n, vmin, vmax):
    """
    Helper function to make an array of random numbers having shape (n, )
    with each number distributed Uniform(vmin, vmax).
    """
    return (vmax - vmin)*np.random.rand(n) + vmin

fig = plt.figure()
ax = fig.add_subplot(projection='3d')

n = 100

# For each set of style and range settings, plot n random points in the box
# defined by x in [23, 32], y in [0, 100], z in [zlow, zhigh].
for m, zlow, zhigh in [('o', -50, -25), ('^', -30, -5)]:
    xs = randrange(n, 23, 32)
    ys = randrange(n, 0, 100)
    zs = randrange(n, zlow, zhigh)
    ax.scatter(xs, ys, zs, marker=m)

ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')

plt.show()

from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt


fig = plt.figure()
ax = fig.add_subplot(projection='3d')

# Grab some test data.
X, Y, Z = axes3d.get_test_data(0.05)

# Plot a basic wireframe.
ax.plot_wireframe(X, Y, Z, rstride=10, cstride=10)

plt.show()

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值