🤔 从"试错学习"说起
还记得小时候学骑自行车吗?
第一次骑车 → 摔倒了 😵
分析原因:身体太僵硬,握把太紧
调整动作:放松身体,轻握把手
第二次骑车 → 还是摔了 😵
再次分析:眼睛看地面,没看前方
继续调整:抬头看路,保持平衡
...
第十次骑车 → 成功了! 🎉
这就是"试错学习"的本质:尝试 → 失败 → 分析原因 → 调整 → 再尝试
反向传播就是神经网络版本的"试错学习"!
🎯 核心思想:责任的分配
想象一个团队项目失败了:
项目失败 💥
├── 项目经理:战略方向错误 (责任40%)
├── 程序员:代码bug太多 (责任35%)
├── 设计师:界面太复杂 (责任20%)
└── 测试员:测试不充分 (责任5%)
→ 每个人按比例承担责任,针对性改进
反向传播也是这样:网络预测错误时,算法会精确地计算每个连接应该承担多少责任,然后相应调整权重。
🧮 从最简单的例子开始
📚 案例:预测房价(单神经元)
假设我们有一个超级简单的"神经网络"(其实就是线性回归):
房价 = w × 面积 + b
import numpy as np
import matplotlib.pyplot as plt
def simple_neuron_learning():
"""演示单个神经元的反向传播学习过程"""
# 训练数据:面积(㎡) → 房价(万)
areas = np.array([50, 80, 100, 120, 150, 180])
prices = np.array([80, 120, 150, 180, 220, 260])
# 初始化参数
w = 1.0 # 权重:面积对房价的影响系数
b = 0.0 # 偏置:基础房价
learning_rate = 0.01
print("=== 单个神经元学习过程演示 ===")
print("真实关系:房价 ≈ 1.4 × 面积 + 10")
print("初始参数:w = %.1f, b = %.1f" % (w, b))
print()
print("轮次 w b 损失 预测(100㎡)")
print("-" * 50)
losses = [] # 记录损失变化
for epoch in range(50):
# 前向传播:计算预测值
predictions = w * areas + b
# 计算损失(均方误差)
loss = np.mean((predictions - prices) ** 2)
losses.append(loss)
# 反向传播:计算梯度
# 损失函数 L = (1/n) * Σ(y_pred - y_true)²
# ∂L/∂w = (2/n) * Σ[(y_pred - y_true) * x]
# ∂L/∂b = (2/n) * Σ(y_pred - y_true)
dw = (2/len(areas)) * np.sum((predictions - prices) * areas)
db = (2/len(areas)) * np.sum(predictions - prices)
# 更新参数(梯度下降)
w -= learning_rate * dw
b -= learning_rate * db
if epoch % 10 == 0 or epoch == 49:
pred_100 = w * 100 + b
print("%2d %.3f %.3f %.1f %.1f万" % (epoch, w, b, loss, pred_100))
# 可视化学习过程
plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.plot(range(50), losses, 'b-', linewidth=2)
plt.xlabel('训练轮次')
plt.ylabel('损失值')
plt.title('损失函数的下降过程')
plt.grid(True, alpha=0.3)
plt.axhline(y=0, color='red', linestyle='--', alpha=0.5)
plt.subplot(1, 2, 2)
plt.scatter(areas, prices, color='blue', s=80, label='真实数据')
# 绘制拟合直线
areas_smooth = np.linspace(40, 190, 100)
prices_fit = w * areas_smooth + b
plt.plot(areas_smooth, prices_fit, 'red', linewidth=2, label='学习到的直线')
plt.xlabel('面积(㎡)')
plt.ylabel('房价(万)')
plt.title('神经网络学到的房价预测模型')
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
print(f"\n学习结果:")
print(f"最终参数:w = {w:.3f}, b = {b:.3f}")
print(f"拟合方程:房价 = {w:.3f} × 面积 + {b:.3f}")
simple_neuron_learning()
关键点解析:
dw和db就是梯度:告诉我们应该往哪个方向调整参数learning_rate控制步长:太大容易跳过最优解,太小学得慢- 损失函数逐渐下降:说明网络在不断改进
🕸️ 多层网络的反向传播
🔄 链式法则:反向传播的灵魂
链式法则是反向传播的数学基础。简单说就是:复合函数的导数等于各层导数的乘积。
def chain_rule_demo():
"""用简单例子演示链式法则"""
print("=== 链式法则演示 ===")
print()
# 复合函数:f(x) = sin(x²)
# 设:g(x) = x², h(g) = sin(g)
# 则:f(x) = h(g(x))
# 链式法则:f'(x) = h'(g(x)) × g'(x) = cos(x²) × 2x
def f_simple(x):
"""f(x) = sin(x^2)"""
g = x**2 # 内层函数
h = np.sin(g) # 外层函数
return h
def f_prime_chain(x):
"""用链式法则求导:f'(x) = cos(x²) × 2x"""
g = x**2
dg_dx = 2 * x # g对x的导数
dh_dg = np.cos(g) # h对g的导数
df_dx = dh_dg * dg_dx # 链式法则
return df_dx
def f_prime_numerical(x, eps=1e-6):
"""用数值方法验证导数"""
return (f_simple(x + eps) - f_simple(x - eps)) / (2 * eps)
# 测试几个点
test_points = [0.5, 1.0, 1.5, 2.0]
print("x值 链式法则 数值验证 误差")
print("-" * 40)
for x in test_points:
chain_result = f_prime_chain(x)
num_result = f_prime_numerical(x)
error = abs(chain_result - num_result)
print("%.1f %.6f %.6f %.2e" % (x, chain_result, num_result, error))
print(f"\n链式法则让我们可以:")
print(f"1. 把复杂函数的导数分解为简单部分的乘积")
print(f"2. 从外层向内层逐层计算梯度")
print(f"3. 这正是反向传播的核心思想!")
chain_rule_demo()
🏗️ 两层网络的反向传播详解
让我们构建一个真正的双层网络:2个输入 → 3个隐藏神经元 → 1个输出
class TwoLayerNetwork:
"""
详细的两层神经网络实现,展示完整的反向传播过程
"""
def __init__(self):
# 网络结构:2 → 3 → 1
# 权重矩阵维度:当前层神经元 × 前一层神经元
self.W1 = np.random.randn(2, 3) * 0.5 # 输入层→隐藏层:2×3
self.b1 = np.random.randn(3) * 0.5 # 隐藏层偏置:3
self.W2 = np.random.randn(3, 1) * 0.5 # 隐藏层→输出层:3×1
self.b2 = np.random.randn(1) * 0.5 # 输出层偏置:1
# 存储中间结果用于反向传播
self.z1 = None # 隐藏层加权输入
self.a1 = None # 隐藏层激活输出
self.z2 = None # 输出层加权输入
self.a2 = None # 输出层激活输出
def sigmoid(self, x):
"""Sigmoid激活函数"""
x = np.clip(x, -250, 250) # 防止数值溢出
return 1 / (1 + np.exp(-x))
def sigmoid_derivative(self, x):
"""Sigmoid函数的导数"""
return x * (1 - x)
def forward(self, X):
"""前向传播"""
# 隐藏层计算
self.z1 = np.dot(X, self.W1) + self.b1 # 加权求和
self.a1 = self.sigmoid(self.z1) # 激活函数
# 输出层计算
self.z2 = np.dot(self.a1, self.W2) + self.b2
self.a2 = self.sigmoid(self.z2)
return self.a2
def backward(self, X, y, learning_rate=0.1):
"""
反向传播:从输出层向输入层传播误差
这是最核心的部分!
"""
m = X.shape[0] # 样本数量
# ===== 第一步:计算输出层误差 =====
# δ₂ = (a₂ - y) ⊙ σ'(z₂)
# 其中⊙表示逐元素相乘
delta2 = (self.a2 - y) * self.sigmoid_derivative(self.a2)
# ===== 第二步:计算隐藏层误差 =====
# δ₁ = (W₂ᵀδ₂) ⊙ σ'(z₁)
# 注意:这里用到了链式法则!
delta1 = np.dot(delta2, self.W2.T) * self.sigmoid_derivative(self.a1)
# ===== 第三步:计算梯度 =====
# dW₂ = (1/m) × a₁ᵀδ₂
dW2 = (1/m) * np.dot(self.a1.T, delta2)
# db₂ = (1/m) × Σδ₂
db2 = (1/m) * np.sum(delta2, axis=0, keepdims=True)
# dW₁ = (1/m) × Xᵀδ₁
dW1 = (1/m) * np.dot(X.T, delta1)
# db₁ = (1/m) × Σδ₁
db1 = (1/m) * np.sum(delta1, axis=0, keepdims=True)
# ===== 第四步:更新参数 =====
self.W2 -= learning_rate * dW2
self.b2 -= learning_rate * db2
self.W1 -= learning_rate * dW1
self.b1 -= learning_rate * db1
# 返回损失用于监控
loss = np.mean((self.a2 - y) ** 2)
return loss
def train(self, X, y, epochs=1000, learning_rate=0.1, verbose=True):
"""训练网络"""
losses = []
if verbose and epochs <= 20:
print("轮次 损失值")
print("-" * 20)
for epoch in range(epochs):
# 前向传播
predictions = self.forward(X)
# 反向传播
loss = self.backward(X, y, learning_rate)
losses.append(loss)
if verbose and ((epoch + 1) % 100 == 0 or epochs <= 20):
if epochs <= 20:
print("%2d %.4f" % (epoch + 1, loss))
elif (epoch + 1) % 200 == 0:
print("轮次 %d: 损失 = %.4f" % (epoch + 1, loss))
return losses
# 演示两层网络学习XOR问题
def demonstrate_two_layer_backprop():
"""演示两层网络的反向传播学习XOR"""
print("=== 两层神经网络学习XOR问题 ===")
print()
# XOR训练数据
X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = np.array([[0], [1], [1], [0]])
print("XOR真值表:")
for i in range(len(X)):
print("%.0f XOR %.0f = %.0f" % (X[i, 0], X[i, 1], y[i, 0]))
# 创建并训练网络
network = TwoLayerNetwork()
print(f"\n初始随机参数:")
print(f"W1 shape: {network.W1.shape}, W2 shape: {network.W2.shape}")
# 训练前测试
print(f"\n训练前预测:")
initial_pred = network.forward(X)
for i in range(len(X)):
pred = 1 if initial_pred[i, 0] > 0.5 else 0
print("%.0f XOR %.0f = %.3f (预测: %.0f)" % (X[i, 0], X[i, 1], initial_pred[i, 0], pred))
# 训练网络
print(f"\n开始训练...")
losses = network.train(X, y, epochs=1000, learning_rate=1.0, verbose=True)
# 训练后测试
print(f"\n训练后预测:")
final_pred = network.forward(X)
for i in range(len(X)):
pred = 1 if final_pred[i, 0] > 0.5 else 0
correct = "✓" if pred == y[i, 0] else "✗"
print("%.0f XOR %.0f = %.3f (预测: %.0f) %s" % (X[i, 0], X[i, 1], final_pred[i, 0], pred, correct))
# 可视化损失下降
plt.figure(figsize=(10, 6))
plt.plot(losses, 'b-', linewidth=2)
plt.xlabel('训练轮次')
plt.ylabel('损失值')
plt.title('反向传播:损失函数的指数式下降')
plt.grid(True, alpha=0.3)
# 标记关键点
plt.axvline(x=0, color='red', linestyle='--', alpha=0.5, label='开始')
plt.axvline(x=len(losses)-1, color='green', linestyle='--', alpha=0.5, label='结束')
plt.legend()
plt.show()
print(f"\n成功!网络学会了XOR逻辑!")
print(f"最终损失: {losses[-1]:.6f} (初始损失: {losses[0]:.6f})")
demonstrate_two_layer_backprop()
🔍 深入理解:梯度下降的三种形式
📈 批量、随机、小批量梯度下降
def gradient_descent_comparison():
"""比较三种梯度下降方法"""
# 创建简单的二次函数:f(x) = x²
def quadratic(x):
return x**2
def derivative(x):
return 2*x
# 三种方法的演示
x_init = 5.0
learning_rate = 0.1
steps = 20
# 1. 批量梯度下降(BGD):使用全部数据计算梯度
x_bgd = x_init
bgd_path = [x_bgd]
for step in range(steps):
grad = derivative(x_bgd)
x_bgd -= learning_rate * grad
bgd_path.append(x_bgd)
# 2. 随机梯度下降(SGD):每次用一个样本
# 这里我们模拟:每次添加一个小的随机扰动
x_sgd = x_init
sgd_path = [x_sgd]
for step in range(steps):
# 添加随机噪声模拟单个样本的噪声
noise = np.random.normal(0, 0.5)
grad = derivative(x_sgd) + noise
x_sgd -= learning_rate * grad
sgd_path.append(x_sgd)
# 3. 小批量梯度下降(Mini-batch):使用部分数据
x_mini = x_init
mini_path = [x_mini]
for step in range(steps):
# 部分噪声:介于BGD和SGD之间
noise = np.random.normal(0, 0.2)
grad = derivative(x_mini) + noise
x_mini -= learning_rate * grad
mini_path.append(x_mini)
# 可视化比较
plt.figure(figsize=(12, 8))
# 绘制函数曲线
x_vals = np.linspace(-6, 6, 200)
y_vals = quadratic(x_vals)
plt.plot(x_vals, y_vals, 'k-', linewidth=2, label='f(x) = x²')
# 绘制优化路径
plt.plot(bgd_path, [quadratic(x) for x in bgd_path], 'bo-',
linewidth=2, markersize=4, label='批量梯度下降(BGD)')
plt.plot(sgd_path, [quadratic(x) for x in sgd_path], 'ro-',
linewidth=1, markersize=3, alpha=0.7, label='随机梯度下降(SGD)')
plt.plot(mini_path, [quadratic(x) for x in mini_path], 'go-',
linewidth=2, markersize=4, label='小批量梯度下降(Mini-batch)')
plt.xlabel('x')
plt.ylabel('f(x)')
plt.title('三种梯度下降方法比较')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
print("三种梯度下降方法对比:")
print("=" * 50)
print("方法 | 优点 | 缺点")
print("-" * 50)
print("批量(BGD) | 稳定收敛,梯度准确 | 计算量大,内存消耗高")
print("随机(SGD) | 计算快,可在线学习 | 波动大,收敛不稳定")
print("小批量(Mini) | 平衡速度和稳定性 | 需要选择合适批量大小")
print()
print("现代深度学习主要使用小批量梯度下降!")
gradient_descent_comparison()
🛠️ 用sklearn体验反向传播
from sklearn.neural_network import MLPRegressor
from sklearn.metrics import mean_squared_error
import matplotlib.pyplot as plt
def sklearn_backprop_demo():
"""用sklearn展示反向传播的实际应用"""
print("=== sklearn中的反向传播实战 ===")
# 创建非线性数据:y = x² + 噪声
np.random.seed(42)
X = np.linspace(-2, 2, 100).reshape(-1, 1)
y_true = X.flatten()**2
y_noisy = y_true + np.random.normal(0, 0.2, 100)
print(f"数据:y = x² + 噪声")
print(f"数据点数:{len(X)}")
# 使用神经网络拟合(sklearn内部使用反向传播)
mlp = MLPRegressor(
hidden_layer_sizes=(10, 5), # 两个隐藏层
activation='tanh',
solver='adam', # Adam优化器(改进的梯度下降)
learning_rate_init=0.01,
max_iter=2000,
random_state=42
)
# 训练过程可视化
print(f"\n训练过程(每100轮显示一次):")
print("轮次 损失值")
print("-" * 20)
# 自定义回调函数显示训练进度
class ProgressCallback:
def __init__(self):
self.losses = []
def __call__(self, estimator, X, y):
loss = estimator.loss_
self.losses.append(loss)
if len(self.losses) % 100 == 0 or len(self.losses) == 1:
print("%4d %.6f" % (len(self.losses), loss))
return False
callback = ProgressCallback()
# 重新训练以捕获回调
mlp.set_params(max_iter=1) # 先设置单次迭代
for i in range(2000 // 100): # 分2000/100=20次训练
mlp.partial_fit(X, y_noisy)
if (i + 1) % 10 == 0 or i == 0: # 每1000轮显示
current_loss = mean_squared_error(y_noisy, mlp.predict(X))
print("轮次 %d: 损失 = %.6f" % ((i + 1) * 100, current_loss))
# 最终训练
mlp.set_params(max_iter=2000)
mlp._random_state = np.random.RandomState(42) # 重置随机种子
mlp.fit(X, y_noisy)
# 预测和评估
y_pred = mlp.predict(X)
final_loss = mean_squared_error(y_noisy, y_pred)
print(f"\n最终训练损失: {final_loss:.6f}")
# 可视化拟合结果
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
plt.scatter(X, y_noisy, alpha=0.6, color='blue', label='带噪声数据')
plt.plot(X, y_true, 'g-', linewidth=2, label='真实函数 y=x²')
plt.plot(X, y_pred, 'r-', linewidth=2, label='神经网络拟合')
plt.xlabel('x')
plt.ylabel('y')
plt.title('神经网络拟合非线性函数')
plt.legend()
plt.grid(True, alpha=0.3)
plt.subplot(1, 2, 2)
# 绘制损失下降曲线(模拟)
epochs = range(1, 2001, 10)
simulated_losses = [final_loss * (1 + np.exp(-e/200)) for e in epochs] # 模拟下降曲线
plt.plot(epochs, simulated_losses, 'b-', linewidth=2)
plt.xlabel('训练轮次')
plt.ylabel('损失值')
plt.title('反向传播:损失函数的下降过程')
plt.yscale('log')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
print(f"神经网络成功学会了非线性关系!")
print(f"网络结构:输入层(1) → 隐藏层(10, 5) → 输出层(1)")
sklearn_backprop_demo()
🚨 反向传播的常见问题和解决方案
⚠️ 梯度消失和梯度爆炸
def gradient_problems():
"""演示梯度消失和梯度爆炸问题"""
print("=== 梯度消失和梯度爆炸问题 ===")
print()
# 1. 梯度消失:Sigmoid激活函数在深层网络中
def sigmoid_vanishing_demo():
print("1️⃣ 梯度消失问题:")
print(" 深层网络中使用Sigmoid激活函数时,")
print(" 梯度在反向传播过程中指数级减小,导致浅层权重几乎不更新。")
# 演示Sigmoid导数的衰减
x = np.linspace(-5, 5, 100)
sigmoid = 1 / (1 + np.exp(-x))
sigmoid_deriv = sigmoid * (1 - sigmoid)
plt.figure(figsize=(10, 4))
plt.subplot(1, 2, 1)
plt.plot(x, sigmoid, 'b-', linewidth=2)
plt.title('Sigmoid函数')
plt.grid(True, alpha=0.3)
plt.subplot(1, 2, 2)
plt.plot(x, sigmoid_deriv, 'r-', linewidth=2)
plt.title('Sigmoid导数(在|x|>2时接近0)')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
print(" 观察:当|x|>2时,Sigmoid导数接近0,梯度几乎消失!")
# 2. 梯度爆炸:权重初始化过大时
def exploding_gradients_demo():
print("2️⃣ 梯度爆炸问题:")
print(" 如果权重初始化过大,激活值会变得很大,")
print(" 导致Sigmoid饱和,或者ReLU产生过大的梯度。")
# 演示大权重的影响
x = np.array([1.0, 2.0, 3.0])
small_weights = np.array([0.1, 0.1, 0.1])
large_weights = np.array([10.0, 10.0, 10.0])
small_output = np.sum(x * small_weights)
large_output = np.sum(x * large_weights)
print(f" 输入: {x}")
print(f" 小权重 {small_weights}: 输出 = {small_output:.3f}")
print(f" 大权重 {large_weights}: 输出 = {large_output:.1f}")
print(f" 大权重导致激活值过大,反向传播时梯度爆炸!")
sigmoid_vanishing_demo()
exploding_gradients_demo()
print()
print("🛠️ 解决方案:")
print("• 使用ReLU族激活函数替代Sigmoid")
print("• 使用Batch Normalization规范化激活值")
print("• 使用残差连接(ResNet)")
print("• 使用合适的权重初始化策略")
print("• 使用梯度裁剪防止梯度爆炸")
gradient_problems()
🧠 反向传播的直观理解
🎭 类比:公司管理的层级传递
def intuitive_understanding():
"""用公司管理类比反向传播"""
print("=== 反向传播的类比:公司管理 ===")
print()
analogy = """
🏢 公司层级结构:
CEO (输出层) ← 部门经理 (隐藏层) ← 普通员工 (输入层)
📊 业绩考核过程:
1️⃣ 前向传播(制定计划):
• 员工汇报工作情况 (输入数据)
• 部门经理汇总评估 (隐藏层计算)
• CEO制定公司业绩目标 (输出预测)
2️⃣ 发现偏差(计算损失):
• 实际业绩 vs 预期目标 = 损失
• "我们亏了100万!" 😱
3️⃣ 反向传播(追责和改进):
• CEO: "我制定的目标有问题!" (输出层梯度)
• 部门经理: "我的团队执行不力!" (隐藏层梯度)
• 员工: "我的工作方法需要改进!" (输入层梯度)
4️⃣ 参数更新(改进措施):
• CEO调整战略 (更新输出层权重)
• 部门经理改进管理方法 (更新隐藏层权重)
• 员工学习新技能 (更新输入层权重)
🔄 持续改进:
每月重复这个过程,公司越来越高效!
神经网络也是通过无数次这样的循环变得"聪明"!
"""
print(analogy)
# 可视化这个类比
fig, ax = plt.subplots(figsize=(12, 8))
# 绘制公司层级图
levels = ['输入层\n(员工)', '隐藏层\n(部门经理)', '输出层\n(CEO)']
positions = [(0, 0), (0, 1), (0, 2)]
# 绘制节点
for i, (level, pos) in enumerate(zip(levels, positions)):
circle = plt.Circle(pos, 0.3, color=f'C{i}', alpha=0.7)
ax.add_patch(circle)
ax.text(pos[0], pos[1], level, ha='center', va='center', fontweight='bold')
# 绘制连接
ax.arrow(-0.3, 0.1, 0, 0.6, head_width=0.05, head_length=0.05, fc='gray', ec='gray')
ax.arrow(-0.3, 1.1, 0, 0.6, head_width=0.05, head_length=0.05, fc='gray', ec='gray')
# 前向传播箭头(向下)
ax.arrow(0.3, 2, 0, -1.6, head_width=0.05, head_length=0.05, fc='blue', ec='blue', alpha=0.7)
ax.text(0.5, 1, '前向传播\n(制定计划)', ha='left', color='blue')
# 反向传播箭头(向上)
ax.arrow(0.3, 0, 0, 1.6, head_width=0.05, head_length=0.05, fc='red', ec='red', alpha=0.7)
ax.text(0.5, 1, '反向传播\n(追责改进)', ha='left', color='red')
ax.set_xlim(-1, 1)
ax.set_ylim(-0.5, 2.5)
ax.set_aspect('equal')
ax.axis('off')
ax.set_title('反向传播类比:公司管理层级', fontsize=14, fontweight='bold')
plt.tight_layout()
plt.show()
intuitive_understanding()
📝 本篇小结
- 反向传播的本质:从错误中学习,按责任分配调整权重
- 核心工具:链式法则让复合函数的导数计算成为可能
- 学习过程:前向传播预测 → 计算损失 → 反向传播误差 → 更新权重
- 梯度下降:有三种形式(批量、随机、小批量),各有优劣
- 常见问题:梯度消失和梯度爆炸,有相应的解决方案
- 直观理解:像公司管理一样,从CEO到员工层层追责和改进
🎯 练习题
- 手工推导:对简单的 y = wx + b,手工推导反向传播的梯度计算公式
- 参数实验:改变学习率,观察对训练过程的影响(太快会跳过最优解,太慢学得慢)
- 激活函数对比:尝试用Sigmoid、Tanh、ReLU训练同一问题,观察梯度传播的差异
- 网络深度:尝试增加网络层数,观察是否会出现梯度消失问题
- 可视化学习:绘制不同层的权重在训练过程中的变化
🔮 下一篇预告
第9篇:PyTorch入门——让电脑帮我们造AI
经过前面的学习,我们已经理解了神经网络的核心原理。但现在有个问题:
手工实现神经网络太麻烦了! 需要处理矩阵运算、反向传播、GPU加速等复杂细节。
这时候就需要深度学习框架了!PyTorch就像是"神经网络的乐高积木":
- 我们只需要搭建网络结构
- 框架自动处理复杂的数学运算
- 支持GPU加速,训练速度飞快
- 丰富的工具和库,让AI开发变得简单
我们将学习如何使用PyTorch快速构建和训练各种神经网络,把理论转化为实际的AI应用!准备好进入工业化AI开发的世界了吗? 🚀

9万+

被折叠的 条评论
为什么被折叠?



