多层全连接神经网络(二)

 线性回归的原理,如果有需要,可以单独拿出来讲。

一维线性回归的代码实现

        首先我们随便给出一些点:

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)

        通过matplotlib画出来就是这个样子,如图3.4所示。

        我们想要做的事情就是找一条直线去逼近这些点,也就是希望这条直线离这些点的距离之和最小,先将 numpy.array 转换成 Tensor,因为 PyTorch 里面的处理单元是 Tensor,按之前讲的方法,这就特别简单了:

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

        接着需要建立模型,根据上一节 PyTorch 的基础知识,这样来定义一个简单的模型:

class LinearRegression(nn.Module):
    def __init__(self):
        super(LinearRegression, self).__init__()
        self.linear = nn.Linear(1, 1)  # input and output is 1 dimension

    def forward(self, x):
        out = self.linear(x)
        return out


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

        这里我们就定义了一个超级简单的模型 y=wx+b,输入参数是一维,输出参数也是一维,这就是一条直线,当然这里可以根据你想要的输入输出维度进行更改,我们希望去优化参数 w 和 b 能够使得这条直线尽可能接近这些点,如果支持 GPU 加速,可以通过 model.cuda() 将模型放到 GPU上。
        然后定义损失函数和优化函数,这里使用均方误差作为优化函数,使用梯度下降进行优化:

criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=1e-4)

        接着就可以开始训练我们的模型了:

num_epochs = 1000
for epoch in range(num_epochs):
    if torch.cuda.is_available():
        inputs = Variable(x_train).cuda()
        target = Variable(y_train).cuda()
    else:
        inputs = Variable(x_train)
        target = Variable(y_train)
    # forward
    out = model(inputs)
    loss = criterion(out, target)
    # backward
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    if (epoch + 1) % 20 == 0:
        print('Epoch[{}/{}], loss: {:.6}'.
              format(epoch + 1, num_epochs, loss.item()))

        定义好我们要跑的 epoch 个数,然后将数据变成 Variable 放入计算图,然后通过 out = model(inputs) 得到网络前向传播得到的结果,通过 loss = criterion(out,target) 得到损失函数,然后归零梯度,做反向传播和更新参数,特别要注意的是,每次做反向传播之前都要归零梯度,optimizer.zero_grad()。不然梯度会累加在一起,造成结果不收敛。在训练的过程中隔一段时间就将损失函数的值打印出来看看,确保我们的模型误差越来越小。注意 loss.data[0],首先 loss 是一个 Variable,所以通过 loss.data 可以取出一个 Tensor,再通过 loss.data[0] 得到一个 int 或者 float 类型的数据,这样我们才能够打印出相应的数据。
        做完训练之后可以预测一下结果。

model.eval()
predict = model(Variable(x_train))
predict = predict.data.cpu().numpy()
plt.plot(x_train.cpu().numpy(), y_train.cpu().numpy(), 'ro', label='Original data')
plt.plot(x_train.cpu().numpy(), predict, label='Fitting Line')
plt.show()

        首先需要通过 model.eval() 将模型变成测试模式,这是因为有一些层操作,比如 Dropout 和 BatchNommalization 在训练和测试的时候是不一样的,所以我们需要通过这样一个操作来转换这些不一样的层操作。然后将测试数据放入网络做前向传播得到结果,最后画出的结果如图 3.5所示。

        这样我们就通过 PyTorch 解决了一个简单的一元回归问题,得到了一条直线去尽可能逼近这些离散的点。

多项式回归

        对于一般的线性回归,由于该函数拟合出来的是一条直线,所以精度欠佳,我们可以考虑多项式回归,也就是提高每个属性的次数,而不再是只使用一次去回归目标函数。
        原理和之前的线性回归是一样的,只不过这里用的是高次多项式而不是简单的一次线性多项式。
        首先给出我们想要拟合的方程:

然后可以设置参数方程:

我们希望每一个参数都能够学习到和真实参数很接近的结果。

        下面来看看如何用PyTorch 实现这个简单的任务。

        首先需要预处理数据,也就是需要将数据变成一个矩阵的形式:

在 PyTorch 里面使用 torch.cat() 函数来实现 Tensor 的拼接:

def make_features(x):
    """Builds features i.e.a matrix with colums [x,x^2,x^3]."""
    x = x.unsqueeze(1)
    return torch.cat([x ** i for i in range(1, 4)], 1)

        对于输入的几个数据,我们将其扩展成上面矩阵所示的样子。

        然后定义好真实的函数:

W_target = torch.FloatTensor([0.5, 3, 2.4]).unsqueeze(1)
b_target = torch.FloatTensor([0.9])


def f(x):
    """Approximated function."""
    return x.mm(W_target) + b_target[0]

        这里的权重已经定义好了,unsqueeze(1) 是将原来的 tensor 大小由3变成(3,1),x.mm(W_target) 表示做矩阵乘法,f(x) 就是每次输入一个 x 得到一个 y 的真实函数。

        在进行训练的时候我们需要采样一些点,可以随机生成一些数来得到每次的训练集:

def get_batch(batch_size=32):
    """Builds a batch i.e.(x,f(x))pair."""
    random = torch.randn(batch_size)
    x = make_features(random)
    y = f(x)
    if torch.cuda.is_available():
        return Variable(x).cuda(), Variable(y).cuda()
    else:
        return Variable(x), Variable(y)

        通过上面这个雨数我们每次取 batch_size 这么多个数据点,然后将其转换成矩阵的形式,再把这个值通过函数之后的结果也返回作为真实的目标。
        然后可以定义多项式模型:

# Define model
class poly_model(nn.Module):
    def __init__(self):
        super(poly_model, self).__init__()
        self.poly = nn.Linear(3, 1)

    def forward(self, x):
        out = self.poly(x)
        return out



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

        这里的模型输入是3维,输出是1维,跟之前定义的线性模型只有很小的差别

        然后我们定义损失函数和优化器:

criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=1e-3)

        同样使用均方误差来衡量模型的好坏,使用随机梯度下降来优化模型,然后开始训练模型:

epoch = 0
while True:
    # Get data
    batch_x, batch_y = get_batch()
    # forward pass
    output = model(batch_x)
    loss = criterion(output, batch_y)
    print_loss = loss.data[0]
    # Reset gradients
    optimizer.zero_grad()
    # Backward pass
    loss.backward()
    # update parameters
    optimizer.step()
    epoch += 1
    if print_loss < 1e-3:
        break

        这里我们希望模型能够不断地优化,直到实现我们设立的条件,取出的32个点的均方误差能够小于 0.001。
        运行程序可以得到如图3.6所示的结果。

        将真实函数的数据点和拟合的多项式画在同一张图上,我们可以得到如图3.7所示的结果。

        从两个结果来看,我们已经很接近真实的函数了。现实世界中很多问题都不是简单的线性回归,涉及很多复杂的非线性模型,而线性模型是机器学习中最重要的模型之一,它的统计思想及其非常直观的解释性仍然可以给我们一些启发。

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-18 11:54:02       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-18 11:54:02       71 阅读
  3. 在Django里面运行非项目文件

    2024-07-18 11:54:02       58 阅读
  4. Python语言-面向对象

    2024-07-18 11:54:02       69 阅读

热门阅读

  1. Docker 容器中的 Docker Compose 简介

    2024-07-18 11:54:02       23 阅读
  2. Spring boot 2.0 升级到 3.3.1 的相关问题 (三)

    2024-07-18 11:54:02       22 阅读
  3. NLP篇10 NLP总结

    2024-07-18 11:54:02       18 阅读
  4. 自然语言处理NLP--文本相似度面试题

    2024-07-18 11:54:02       16 阅读
  5. vue中获取剪切板中的内容

    2024-07-18 11:54:02       23 阅读
  6. 面向过程编程和面向对象编程

    2024-07-18 11:54:02       19 阅读
  7. 【Vue】 @/ 和 ./ 区别

    2024-07-18 11:54:02       20 阅读
  8. 特朗普主题meme币受消息面和选情影响大幅波动

    2024-07-18 11:54:02       19 阅读
  9. Git【撤销远程提交记录】

    2024-07-18 11:54:02       22 阅读