手算神经网络

本文涉及的产品
RDS DuckDB + QuickBI 企业套餐,8核32GB + QuickBI 专业版
简介: 本文介绍了使用2×3×1神经网络实现房价预测的全过程。首先通过手动计算演示了单个样本的前向传播和反向传播,包括权重初始化和梯度更新。随后使用PyTorch实现了完整的神经网络模型,包含数据准备、网络结构定义、损失函数计算和优化器设置。在训练过程中记录了损失值变化,并可视化展示训练效果。最后提供了一个挖空版本的代码框架,帮助读者逐步完成神经网络的关键实现步骤,包括导入包、定义网络框架、数据准备、训练循环和结果可视化等模块。通过这个完整的项目实践,读者可以掌握神经网络从理论到实现的全流程。

 矩阵求导基础

image.gif


手动计算

问题的背景:预测一套房产的价格(一个连续数值)

输入:面积 (0.5), 房龄 (0.8)  输出:现在房子的价格

    为了把问题简单化,这里的话我们使用了2×3×1 网络结构(2 输入 → 3 隐藏 → 1 输出),保持

无偏置项的简化原则。

网络的结构如下:

前向传播

   在这个网络结构中,根据给定的房产面积和房龄,我们预测的房价是 0.260(这个值是归一化后

的结果)。

计算损失函数

现在我们有了前向传播的结果,我们可以用它来演示反向传播了。

我们假设这套房产的真实价格 (Y) 是 0.4。

我们将使用均方误差(MSE)损失函数,这在回归问题中是标准做法:

image.gif

反向传播和更新参数

image.gif


代码实现

一个样本的神经网络的实现

        在 PyTorch 和大多数现代深度学习框架中,惯例是使用 行向量(Row Vector)作为单个样本

的输入:手动计算时习惯用 X 形式 (列向量),但 PyTorch 采用 X 形式 (行向量) 来处理输

入。

import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
# 1. 定义网络结构 (2 -> 3 -> 1)
class SimpleNet(nn.Module):
    def __init__(self, W1_data, W2_data):
        super(SimpleNet, self).__init__()
        # 隐藏层 (Input=2, Output=3)
        self.fc1 = nn.Linear(2, 3, bias=False)  # 设置 bias=False 对应“无偏置项”
        # 输出层 (Input=3, Output=1)
        self.fc2 = nn.Linear(3, 1, bias=False)  # 设置 bias=False
        # 将我们手算的初始权重加载到网络中
        # 注意 PyTorch 的 nn.Linear 默认使用 W^T 形式,即 W 是 (out_features, in_features)
        with torch.no_grad():
            self.fc1.weight.data = W1_data  # W1 是 3x2 
            self.fc2.weight.data = W2_data  # W2 是 1x3
    def forward(self, x):
        # 隐藏层:Z1 = W1^T * X -> A1 = ReLU(Z1)
        # 注意:PyTorch 内部处理了 W^T * X,我们只需传入 W 即可
        Z1 = self.fc1(x) 
        A1 = nn.functional.relu(Z1)
        # 输出层:Z2 = W2^T * A1 -> A2 = Z2 (恒等激活)
        Z2 = self.fc2(A1)
        A2 = Z2  # A2 = Z2 for identity activation (regression)
        return Z2, A1, Z2 # 返回 Z2, A1, A2 方便检查中间值
# 2. 定义输入和参数
# 注意 PyTorch 默认是 FloatTensor,且输入需要是 [Batch_Size, Features]
# X (1x2 矩阵): [面积, 房龄]
X_tensor = torch.tensor([[0.5, 0.8]], dtype=torch.float32)
# W1 (3x2 矩阵): 对应 PyTorch 的 (out_features, in_features)
W1_init = torch.tensor([
    [0.1, 0.2],  # W1^T 的第一行 (Z1,1)
    [0.3, 0.4],  # W1^T 的第二行 (Z1,2)
    [0.5, 0.6]   # W1^T 的第三行 (Z1,3)
], dtype=torch.float32)
# W2 (1x3 矩阵): 对应 PyTorch 的 (out_features, in_features)
W2_init = torch.tensor([
    [-0.9, 0.8, 0.1]
], dtype=torch.float32)
# 真实标签 Y
Y_tensor = torch.tensor([[0.4]], dtype=torch.float32)
# 学习率
learning_rate = 0.1
# 3. 初始化模型、损失函数和优化器
model = SimpleNet(W1_init, W2_init)
# MSE Loss (PyTorch 默认是 0.5 * (A2 - Y)^2)
criterion = nn.MSELoss() 
optimizer = optim.SGD(model.parameters(), lr=learning_rate)
print("--- 开始前向传播验证 ---")
# 清空之前的梯度
optimizer.zero_grad() 
# 4. 前向传播 (Forward Propagation)
Z2_out, A1_out, A2_pred = model(X_tensor)
# 验证中间结果
print(f"X:\n{X_tensor.numpy()}")
print(f"\nW1 (3x2):\n{model.fc1.weight.data.numpy()}")
print(f"\n隐藏层激活输出 A1 (手算: 0.21, 0.47, 0.73):\n{A1_out.detach().numpy()}")
print(f"\n最终预测 A2 (手算: 0.260):\n{A2_pred.detach().numpy()}")
# 5. 计算损失 (Loss)
loss = criterion(A2_pred, Y_tensor)
print(f"\n真实标签 Y: {Y_tensor.numpy()[0, 0]}")
print(f"损失 L (0.5 * (0.26 - 0.4)^2): {loss.item():.5f}")
# 6. 反向传播 (Backward Propagation)
loss.backward()
# 7. 检查梯度 (Verification of Gradients)
print("\n--- 反向传播梯度验证 (手动计算的梯度值) ---")
# 检查 dL/dW2 (W2 梯度)
# 手算: dL/dW2 = [-0.0294, -0.0658, -0.1022] (转置后)
dL_dW2 = model.fc2.weight.grad
print(f"dL/dW2 (W2 梯度):\n{dL_dW2.numpy()}")
# 检查 dL/dW1 (W1 梯度)
# 手算: dL/dW1 = [[0.0630, -0.0560, -0.0070], [0.1008, -0.0896, -0.0112]]
dL_dW1 = model.fc1.weight.grad
print(f"dL/dW1 (W1 梯度):\n{dL_dW1.numpy()}")
# 8. 权重更新 (Gradient Descent)
optimizer.step()
# 9. 检查更新后的权重 (Verification of New Weights)
print("\n--- 权重更新验证 ---")
# W2_new = W2 - alpha * dL/dW2
W2_new = model.fc2.weight.data
# 手算 W2_new: [-0.8971, 0.8066, 0.1102]
print(f"W2 新权重:\n{W2_new.numpy()}")
# W1_new = W1 - alpha * dL/dW1
W1_new = model.fc1.weight.data
# 手算 W1_new: [[0.0937, 0.3056, 0.5007], [0.1899, 0.4090, 0.6011]]
print(f"W1 新权重:\n{W1_new.numpy()}")

image.gif

image.gif

逐行解析

image.gif

初始化

image.gif

计算第一层

image.gif

计算第二层和损失函数

多个样本的神经网络的实现

   现在我们将会使用的 2×3×1 回归网络来构造一个小型数据集,并定义一个简单的训练循环,展

示网络如何通过多轮迭代(Epochs)来不断学习和减少误差。

们构造四个数据点,代表四种不同房产的面积、房龄实际价格(均已归一化到 0 到 1 之间)。

编号 面积 (X1) 房龄 (X2) 实际价格 (Y) 描述
D1 0.5 0.8 0.40 (我们刚才手算的数据)
D2 0.9 0.2 0.85 新房,面积大,价格高
D3 0.2 0.9 0.15 旧房,面积小,价格低
D4 0.6 0.4 0.50 中等房,价格中等
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
# --- 1. 定义网络模型 ---
class SimpleNet(nn.Module):
    def __init__(self, W1_data, W2_data):
        super(SimpleNet, self).__init__()
        # 隐藏层 (Input=2, Output=3), 无偏置项
        self.fc1 = nn.Linear(2, 3, bias=False) 
        # 输出层 (Input=3, Output=1), 无偏置项
        self.fc2 = nn.Linear(3, 1, bias=False)
        # 加载手动计算的初始权重
        with torch.no_grad():
            # fc1.weight 维度是 (out_features, in_features) 即 (3, 2)
            self.fc1.weight.data = W1_data  
            # fc2.weight 维度是 (out_features, in_features) 即 (1, 3)
            self.fc2.weight.data = W2_data  
    def forward(self, x):
        # 隐藏层:ReLU 激活
        Z1 = self.fc1(x) 
        A1 = nn.functional.relu(Z1)
        # 输出层:恒等激活 (回归)
        A2 = self.fc2(A1)
        return A2
# --- 2. 数据集与初始参数 ---
# 输入特征 X (4x2 矩阵: 4个样本, 2个特征 [面积, 房龄])
X_data = torch.tensor([
    [0.5, 0.8], # D1 (手算起始点)
    [0.9, 0.2], # D2
    [0.2, 0.9], # D3
    [0.6, 0.4]  # D4
], dtype=torch.float32)
# 真实标签 Y (4x1 矩阵: 实际价格)
Y_data = torch.tensor([
    [0.40],
    [0.85],
    [0.15],
    [0.50]
], dtype=torch.float32)
# 初始权重 (与手算时使用的 W1^T 和 W2^T 维度保持一致)
W1_init = torch.tensor([[0.1, 0.2], [0.3, 0.4], [0.5, 0.6]], dtype=torch.float32)
W2_init = torch.tensor([[-0.9, 0.8, 0.1]], dtype=torch.float32)
learning_rate = 0.1
EPOCHS = 50 
# --- 3. 初始化模型、损失函数和优化器 ---
model = SimpleNet(W1_init, W2_init)
criterion = nn.MSELoss() 
optimizer = optim.SGD(model.parameters(), lr=learning_rate)
# --- 4. 训练循环 ---
print("--- 神经网络开始学习 (50 轮训练) ---")
print(f"初始损失: {criterion(model(X_data), Y_data).item():.6f}")
for epoch in range(EPOCHS):
    # 零化梯度
    optimizer.zero_grad() 
    # 前向传播
    predictions = model(X_data)
    # 计算损失
    loss = criterion(predictions, Y_data)
    # 反向传播
    loss.backward()
    # 权重更新 (梯度下降)
    optimizer.step()
    if (epoch + 1) % 10 == 0:
        print(f"Epoch {epoch + 1:2d}/{EPOCHS} | Loss: {loss.item():.6f}")
print("--- 训练结束,网络已学习 ---")
# --- 5. 最终结果展示 ---
final_predictions = model(X_data)
print("\n--- 最终预测与权重对比 ---")
print("样本数据 (面积/房龄):", X_data.numpy().round(2).T)
print("实际价格 Y:           ", Y_data.squeeze().numpy().round(4))
print("最终预测 A2:        ", final_predictions.squeeze().detach().numpy().round(4))
print("\n最终 W1 (2x3) 权重:\n", model.fc1.weight.data.numpy().round(4))
print("\n最终 W2 (1x3) 权重:\n", model.fc2.weight.data.numpy().round(4))

image.gif

image.gif

初始化

第一层的计算

image.gif

第二层的计算

import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt # 导入绘图库
import os
os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"
# --- 1. 定义网络模型 ---
class SimpleNet(nn.Module):
    def __init__(self, W1_data, W2_data):
        super(SimpleNet, self).__init__()
        self.fc1 = nn.Linear(2, 3, bias=False)
        self.fc2 = nn.Linear(3, 1, bias=False)
        with torch.no_grad():
            self.fc1.weight.data = W1_data
            self.fc2.weight.data = W2_data
    def forward(self, x):
        Z1 = self.fc1(x)
        A1 = nn.functional.relu(Z1)
        A2 = self.fc2(A1)
        return A2
# --- 2. 数据集与初始参数 ---
X_data = torch.tensor([
    [0.5, 0.8], [0.9, 0.2], [0.2, 0.9], [0.6, 0.4] 
], dtype=torch.float32)
Y_data = torch.tensor([
    [0.40], [0.85], [0.15], [0.50]
], dtype=torch.float32)
W1_init = torch.tensor([[0.1, 0.2], [0.3, 0.4], [0.5, 0.6]], dtype=torch.float32)
W2_init = torch.tensor([[-0.9, 0.8, 0.1]], dtype=torch.float32)
learning_rate = 0.1
EPOCHS = 50 
# --- 3. 初始化模型、损失函数和优化器 ---
model = SimpleNet(W1_init, W2_init)
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=learning_rate)
# 新增:用于存储每一步的损失值
loss_history = []
# --- 4. 训练循环 ---
print("--- 神经网络开始学习 ---")
initial_loss = criterion(model(X_data), Y_data).item()
print(f"初始损失: {initial_loss:.6f}")
loss_history.append(initial_loss)
for epoch in range(EPOCHS):
    optimizer.zero_grad()
    predictions = model(X_data)
    loss = criterion(predictions, Y_data)
    
    # 记录当前损失
    loss_history.append(loss.item())
    
    loss.backward()
    optimizer.step()
    
    if (epoch + 1) % 10 == 0:
        print(f"Epoch {epoch + 1:2d}/{EPOCHS} | Loss: {loss.item():.6f}")
print("--- 训练结束 ---")
# --- 5. 损失曲线可视化 ---
plt.figure(figsize=(10, 6))
# 注意:我们记录了 1个初始损失 + 50个训练损失,共 51 个点
plt.plot(range(len(loss_history)), loss_history, label='Training Loss', marker='o', markersize=4, linestyle='-')
plt.title('Loss Curve during Training (MSE)')
plt.xlabel('Epoch (0 is Initial Loss)')
plt.ylabel('Mean Squared Error (MSE)')
plt.grid(True)
plt.legend()
plt.show()
# --- 6. 最终结果展示 (略) ---
final_predictions = model(X_data)
print("\n--- 最终预测与权重对比 ---")
print("实际价格 Y: ", Y_data.squeeze().numpy().round(4))
print("最终预测 A2: ", final_predictions.squeeze().detach().numpy().round(4))

image.gif


挖空版本

   由于AI的出现,详细很多的小伙伴和我一样已经很久没有自己写过代码,或者是项目了,但是我

个人还是觉得,写代码是计算机专业的基本的内容,下面的内容的目的是为了辅助你自己写一个完

整的多个项目神经网络的实现。我会把上面的项目分解成的四个模块的挖空版本,重点突出需要你

自己动手完成的关键步骤和数值。

一般简单任务的框架:

image.gif 编辑

第一个任务:导入我们所需要的包

import (基础张量运算)
import (神经网络模块)
import (优化器)
imoirt (可视化模块)

image.gif

第二个任务:定义网络框架

image.gif

# --- 1. 定义网络模型 (无需修改) ---
class SimpleNet(nn.Module):
    def __init__(self, W1_data, W2_data):
        super(SimpleNet, self).__init__()
        # 隐藏层:2输入, 3输出, 无偏置
        self.fc1 = 
        # 输出层:3输入, 1输出, 无偏置
        self.fc2 = 
        with torch.no_grad():
            self.fc1.weight.data = W1_data
            self.fc2.weight.data = W2_data
    def forward(self, x):
        Z1 = 
        A1 = # ReLU 激活
        A2 =  # 恒等激活 (Z2)
        return A2

image.gif

第3个任务:数据准备与初始化 (Data & Initialization)

这部分定义了训练数据、初始权重和超参数。

# 真实标签 Y (4x1 矩阵)
Y_data = torch.tensor([
    [0.40], 
    [0.85], 
    [0.15], 
    [0.50]
], dtype=torch.float32)
# W1 (3x2): 初始化权重矩阵 W1
W1_init = torch.tensor([
    [0.1, 0.2], 
    [0.3, 0.4], 
    [____, ____] # 请补齐 (0.5, 0.6)
], dtype=torch.float32)
# W2 (1x3): 初始化权重矩阵 W2
W2_init = torch.tensor([[-0.9, 0.8, 0.1]], dtype=torch.float32)
# 超参数
learning_rate =   #把学习率设置成0.1
EPOCHS =           #把迭代次数设置成50次
# --- 3. 初始化模型、损失函数和优化器 (请填充) ---
model =   #初始化模型
criterion = nn.____() # 请选择损失函数 (MSE)
optimizer = optim.____(model.parameters(), lr=learning_rate) # 请选择优化器 (SGD)
# 用于存储每一步的损失值
loss_history = []

image.gif

第4个任务:核心训练循环 (Training Loop)

这部分是反向传播梯度下降逻辑实现的地方。

# --- 4. 训练循环 (请填充反向传播和更新的核心步骤) ---
print("--- 神经网络开始学习 ---")
initial_loss = criterion(model(X_data), Y_data).item()
print(f"初始损失: {initial_loss:.6f}")
loss_history.append(initial_loss)
for epoch in range(EPOCHS):
    # 步骤 1: 零化梯度
    optimizer.____() 
    
    # 步骤 2: 前向传播
    predictions = model(X_data)
    
    # 步骤 3: 计算损失
    loss = criterion(predictions, Y_data)
    
    # 步骤 4: 反向传播
    loss.____()
    
    # 步骤 5: 权重更新 (梯度下降)
    optimizer.____() 
    
    # 记录损失值
    loss_history.append(loss.item())
    
    if (epoch + 1) % 10 == 0:
        print(f"Epoch {epoch + 1:2d}/{EPOCHS} | Loss: {loss.item():.6f}")
print("--- 训练结束 ---")

image.gif

第5个任务:可视化与结果展示 (Visualization & Results)

这部分用于验证训练效果。

# --- 5. 损失曲线可视化 (请补齐绘图指令) ---
plt.figure(figsize=(10, 6))
plt.plot(range(len(loss_history)), loss_history, label='Training Loss', marker='o', markersize=4, linestyle='-')
plt.title('Loss Curve during Training (MSE)')
plt.xlabel('Epoch (0 is Initial Loss)')
plt.ylabel('____') # 请补齐 Y 轴标签
plt.grid(True)
plt.legend()
plt.____() # 请补齐显示图表的指令
# --- 6. 最终结果展示 (请补齐用于提取数值的关键方法) ---
final_predictions = model(X_data)
print("\n--- 最终预测与权重对比 ---")
# 提取最终预测的数值并格式化
print("最终预测 A2: ", final_predictions.squeeze().____().numpy().round(4))
print("\n最终 W1 (3x2) 权重:\n", model.fc1.weight.data.numpy().round(4))
print("\n最终 W2 (1x3) 权重:\n", model.fc2.weight.data.numpy().round(4))

image.gif


目录
相关文章
|
16天前
|
人工智能 自然语言处理 文字识别
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
Qwen3.7-Max是阿里云百炼面向智能体时代推出的新一代旗舰模型,对标GPT-5.5、Claude Opus 4.7等闭源旗舰。该模型支持百万级token上下文窗口,具备顶级推理能力、多模态搜索与视觉理解增强、流式输出低延迟响应等核心优势,覆盖编程、办公、长周期自主执行等复杂场景。同时支持OpenAI接口兼容,便于系统快速迁移。用户可通过Token Plan团队或节省计划等订阅方式灵活调用,适合企业级高要求场景使用。
5871 30
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
|
1天前
|
数据采集 人工智能 前端开发
让 Coding Agent 从黑盒到透明:阿里云 Agent 观测审计数据采集实践
AI Agent 规模化落地带来执行黑盒、行为难追溯、成本难度量三大难题。阿里云基于 OTel 标准,面向 Coding Agent、个人通用助理和框架型 Agent,推出 LoongSuite Pilot、插件及探针等无侵入采集方案,让 Agent 实现可看见、可分析、可审计、可治理。
561 134
|
10天前
|
存储 定位技术 数据库
CodeGraph 如何让 Claude Code减少 7 成工具调用?
CodeGraph 为 Coding Agent 提供本地代码知识图谱,把函数、类、调用链和框架路由提前整理成“项目地图”,减少盲目搜索和文件读取。它不是新 Agent,而是上下文基础设施,让 Agent 更快找到正确代码路径,平均减少 7 成工具调用。
1177 2
|
8天前
|
人工智能 安全 定位技术
CodeGraph深度解析 让Claude Code工具调用直降七成的核心原理与实操教程
如今以Claude Code为代表的AI编程智能体已经成为开发者日常编码、项目重构、漏洞修复的必备工具。但在长期使用过程中,几乎所有开发者都会遇到同一个明显痛点:AI虽然具备强大的代码生成与分析能力,却常常陷入盲目探索的循环中。
959 1
|
17天前
|
人工智能 自然语言处理 供应链
|
8天前
|
人工智能 弹性计算 安全
阿里云618活动时间、活动入口、优惠活动详细解读
2026年阿里云618创新加速季已全面开启,作为年度力度最大的云产品促销活动,本次大促覆盖轻量应用服务器、ECS云服务器、GPU云服务器、数据库、AI算力、安全服务、CDN等全品类产品,推出5亿元算力补贴、新用户限时秒杀、普惠满减、企业专享、免费试用、云大使返佣等多重福利,个人开发者、中小企业、AI团队均可享受专属低价。本文将系统梳理2026年阿里云618活动的完整时间节点、官方参与入口、各类优惠细则、使用规则、热门产品推荐及实操代码,帮助用户精准参与、高效省钱,以最低成本完成上云部署。
764 4
|
8天前
|
运维
欢迎报名|2026 Agentic AICon—智能体基础设施与AgentOps专场,邀您参会
欢迎报名|2026 Agentic AICon—智能体基础设施与AgentOps专场,邀您参会
1432 0