写给程序员的机器学习入门 (三) - 线性模型,激活函数与多层线性模型 (2)

以上可以看作 1 层 1 个神经元,很好理解吧?我们来看看 1 层 2 个神经元:

# 导入 pytorch 类库 >>> import torch # 创建 pytorch 封装的线性模型,设置输入有 3 个输出有 2 个 >>> model = torch.nn.Linear(in_features=3, out_features=2) # 查看线性模型内部包含的参数列表 # 这里一共包含两个参数 # 第一个参数是 2 行 3 列的矩阵分别表示 2 个输出和 3 个输入对应的 w 值 (权重) # 第二个参数表示 2 个输出对应的 b 值 (偏移) >>> list(model.parameters()) [Parameter containing: tensor([[0.1393, 0.5165, 0.2910], [0.2276, 0.1579, 0.1958]], requires_grad=True), Parameter containing: tensor([0.2566, 0.1701], requires_grad=True)] # 定义输入和输出 >>> x = torch.tensor([1, 2, 3], dtype=torch.float) >>> y = torch.tensor([6, -6], dtype=torch.float) # 把输入传给模型 >>> p = model(x) # 查看预测输出值 # 1 * 0.1393 + 2 * 0.5165 + 3 * 0.2910 + 0.2566 = 2.3019 # 1 * 0.2276 + 2 * 0.1579 + 3 * 0.1958 + 0.1701 = 1.3009 >>> p tensor([2.3019, 1.3009], grad_fn=<AddBackward0>) # 计算误差并自动微分 # (abs(2.3019 - 6) + abs(1.3009 - -6)) / 2 = 5.4995 >>> l = (p - y).abs().mean() >>> l tensor(5.4995, grad_fn=<MeanBackward0>) >>> l.backward() # 查看各个参数对应的导函数值 # 因为误差取了 2 个值的平均,所以求导函数值的时候会除以 2 >>> list(model.parameters())[0].grad tensor([[-0.5000, -1.0000, -1.5000], [ 0.5000, 1.0000, 1.5000]]) >>> list(model.parameters())[1].grad tensor([-0.5000, 0.5000])

现在我们来试试用线性模型来学习符合 x_1 * 1 + x_2 * 2 + x_3 * 3 + 8 = y 的数据,输入和输出会使用矩阵定义:

# 引用 pytorch import torch # 给随机数生成器分配一个初始值,使得每次运行都可以生成相同的随机数 # 这是为了让训练过程可重现,你也可以选择不这样做 torch.random.manual_seed(0) # 创建线性模型,设置有 3 个输入 1 个输出 model = torch.nn.Linear(in_features=3, out_features=1) # 创建损失计算器 loss_function = torch.nn.MSELoss() # 创建参数调整器 optimizer = torch.optim.SGD(model.parameters(), lr=0.01) # 随机生成原始数据集,一共 20 组数据,每条数据有 3 个输入 dataset_x = torch.randn((20, 3)) dataset_y = dataset_x.mm(torch.tensor([[1], [2], [3]], dtype=torch.float)) + 8 print(f"dataset_x: {dataset_x}") print(f"dataset_y: {dataset_y}") # 切分训练集 (12 组),验证集 (4 组) 和测试集 (4 组) random_indices = torch.randperm(dataset_x.shape[0]) traning_indices = random_indices[:int(len(random_indices)*0.6)] validating_indices = random_indices[int(len(random_indices)*0.6):int(len(random_indices)*0.8):] testing_indices = random_indices[int(len(random_indices)*0.8):] traning_set_x = dataset_x[traning_indices] traning_set_y = dataset_y[traning_indices] validating_set_x = dataset_x[validating_indices] validating_set_y = dataset_y[validating_indices] testing_set_x = dataset_x[testing_indices] testing_set_y = dataset_y[testing_indices] # 开始训练过程 for epoch in range(1, 10000): print(f"epoch: {epoch}") # 根据训练集训练并修改参数 # 切换模型到训练模式,将会启用自动微分,批次正规化 (BatchNorm) 与 Dropout model.train() # 计算预测值 # 20 行 3 列的矩阵乘以 3 行 1 列的矩阵 (由 weight 转置得到) 等于 20 行 1 列的矩阵 predicted = model(traning_set_x) # 计算损失 loss = loss_function(predicted, traning_set_y) # 打印除错信息 print(f"loss: {loss}, weight: {model.weight}, bias: {model.bias}") # 从损失自动微分求导函数值 loss.backward() # 使用参数调整器调整参数 optimizer.step() # 清空导函数值 optimizer.zero_grad() # 检查验证集 # 切换模型到验证模式,将会禁用自动微分,批次正规化 (BatchNorm) 与 Dropout model.eval() predicted = model(validating_set_x) validating_accuracy = 1 - ((validating_set_y - predicted).abs() / validating_set_y).abs().mean() print(f"validating x: {validating_set_x}, y: {validating_set_y}, predicted: {predicted}") # 如果验证集正确率大于 99 %,则停止训练 print(f"validating accuracy: {validating_accuracy}") if validating_accuracy > 0.99: break # 检查测试集 predicted = model(testing_set_x) testing_accuracy = 1 - ((testing_set_y - predicted).abs() / testing_set_y).abs().mean() print(f"testing x: {testing_set_x}, y: {testing_set_y}, predicted: {predicted}") print(f"testing accuracy: {testing_accuracy}")

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzjsdx.html