尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

从零手写AI:拆解线性回归、神经网络与自注意力机制

从零手写AI:拆解线性回归、神经网络与自注意力机制 在AI技术浪潮席卷全球的今天你是否曾感到困惑那些看似高深莫测的数学模型、复杂精妙的算法逻辑以及支撑起整个AI系统的庞大架构究竟是如何被创造出来的对于许多开发者而言理解AI的原理往往停留在调用API和调整参数层面知其然而不知其所以然。Prof. Tom Yeh的“亲手打造的AI”专栏为我们提供了一条独特的路径——通过回归最原始的手写推导和构建来拆解AI背后的数学、算法与架构。本文将带你深入解读这一理念并尝试用同样的“手写”精神从零开始构建几个核心的AI概念让你不仅会用AI更能亲手“打造”AI。1. 专栏理念与核心价值为什么需要“手写”AI在快餐式的技术学习环境中“手写”构建AI听起来似乎效率低下。然而这正是Prof. Tom Yeh专栏的精髓所在。其核心价值在于建立深刻的理解与直觉。1.1 从“黑盒”到“白盒”打破认知壁垒现代AI框架如TensorFlow, PyTorch封装了极其复杂的运算使得开发者可以快速搭建模型。但这带来了一个副作用模型成了一个“黑盒”。我们输入数据得到结果但对中间发生的矩阵变换、梯度流动、损失计算等关键过程一无所知。这种认知状态是脆弱的一旦模型表现不佳或出现诡异错误排查将异常困难。“手写”意味着我们暂时抛开这些高级框架使用最基础的编程语言如Python的NumPy甚至纸笔去一步步实现某个算法或模型的前向传播、反向传播。这个过程强迫我们直面每一个数学公式和逻辑判断将“黑盒”彻底打开变成完全透明的“白盒”。1.2 构建坚实的数学与算法基础AI的三大支柱是数学、算法和架构。数学线性代数、微积分、概率论是AI的通用语言。例如神经网络的本质是矩阵乘法线性代数和链式法则求导微积分。算法从最简单的线性回归、K-Means聚类到复杂的反向传播、注意力机制都是一套明确的、可执行的步骤序列。架构如何将数学和算法组织起来形成如LeNet、Transformer等高效、可扩展的系统这是工程能力的体现。通过手写实现你将不得不厘清这个损失函数是如何从数学公式翻译成代码的梯度下降的每一步更新权重矩阵究竟发生了什么变化Self-Attention机制中的Q, K, V矩阵是如何计算并产生权重的这种深度的理解是单纯调用model.fit()无法获得的。1.3 培养解决未知问题的能力当你能从零构建一个经典模型时你就获得了拆解任何新论文、新模型的能力。你可以快速识别出新架构中的核心创新点究竟是新的数学变换、新的算法流程还是新的模块组合方式。这种能力让你不仅能复现更能创新。2. 环境准备你的“手写”工作台我们不需要复杂的GPU集群或特定的AI框架。一个纯净的Python环境加上基础的科学计算库就足够了。这模拟了最原始的“从第一性原理出发”的构建环境。核心环境要求Python 3.8: 现代Python环境。NumPy: 用于高效的矩阵和数值计算。这是我们实现所有数学运算的基石。Matplotlib: 用于可视化结果如损失曲线、数据分布、模型决策边界。安装命令# 使用pip安装 pip install numpy matplotlib # 如果你使用Anaconda conda install numpy matplotlib验证安装import numpy as np import matplotlib.pyplot as plt print(fNumPy version: {np.__version__}) # 创建一个简单的数组并运算 a np.array([1, 2, 3]) b np.array([4, 5, 6]) print(fa b {a b}) print(环境准备就绪)我们将在一个Jupyter Notebook或一个简单的Python脚本中完成所有“手写”代码确保每一步都可交互、可验证。3. 核心拆解一从线性回归理解机器学习本质线性回归是机器学习世界的“Hello World”。让我们用手写的方式完整实现它理解模型、损失函数、优化算法这个机器学习铁三角。3.1 数学原理与模型定义线性回归假设目标y和特征x之间存在线性关系y w * x b。 其中w(weight): 权重表示特征的重要性。b(bias): 偏置表示基准值。给定一组数据(x_i, y_i)我们的目标是找到一组参数(w, b)使得模型预测值y_pred_i w * x_i b与真实值y_i尽可能接近。损失函数Loss Function我们使用均方误差MSE来衡量“接近”的程度。Loss (1/N) * Σ(y_i - y_pred_i)^2目标是最小化这个损失函数。优化算法Optimization我们使用梯度下降Gradient Descent。通过计算损失函数对参数w和b的梯度导数并沿着梯度反方向即下降最快的方向更新参数。w w - learning_rate * ∂Loss/∂wb b - learning_rate * ∂Loss/∂b3.2 手写实现代码我们不使用sklearn的LinearRegression而是用NumPy从头实现。import numpy as np import matplotlib.pyplot as plt # 1. 生成模拟数据 np.random.seed(42) # 确保结果可复现 X 2 * np.random.rand(100, 1) # 100个样本1个特征范围[0,2) true_w 4 true_b 3 y true_w * X true_b np.random.randn(100, 1) * 0.5 # 加入噪声 # 2. 初始化模型参数 w np.random.randn(1) # 随机初始化权重 b np.zeros(1) # 偏置初始化为0 learning_rate 0.01 # 学习率 n_iterations 1000 # 迭代次数 # 3. 梯度下降核心循环 loss_history [] # 记录损失变化 for iteration in range(n_iterations): # 前向传播计算预测值 y_pred w * X b # 计算损失 (MSE) loss np.mean((y_pred - y) ** 2) loss_history.append(loss) # 反向传播计算梯度手动求导 # ∂Loss/∂w (2/N) * Σ(y_pred - y) * X # ∂Loss/∂b (2/N) * Σ(y_pred - y) dw (2 / len(X)) * np.dot((y_pred - y).T, X).flatten() db (2 / len(X)) * np.sum(y_pred - y) # 更新参数 w w - learning_rate * dw b b - learning_rate * db # 每100次迭代打印一次 if iteration % 100 0: print(fIteration {iteration}: loss {loss:.4f}, w {w[0]:.4f}, b {b[0]:.4f}) print(f\n训练完成最终参数: w {w[0]:.4f}, b {b[0]:.4f}) print(f真实参数: w {true_w}, b {true_b}) # 4. 可视化结果 plt.figure(figsize(12, 4)) # 子图1数据与拟合线 plt.subplot(1, 2, 1) plt.scatter(X, y, alpha0.7, labelTraining data) X_line np.array([[0], [2]]) # 生成两个点画线 y_line w * X_line b plt.plot(X_line, y_line, r-, linewidth3, labelfOur model: y{w[0]:.2f}x{b[0]:.2f}) plt.xlabel(X) plt.ylabel(y) plt.title(Linear Regression Fit) plt.legend() plt.grid(True) # 子图2损失下降曲线 plt.subplot(1, 2, 2) plt.plot(loss_history) plt.xlabel(Iteration) plt.ylabel(Loss (MSE)) plt.title(Gradient Descent: Loss Convergence) plt.grid(True) plt.tight_layout() plt.show()3.3 代码拆解与思考前向传播y_pred w * X b这就是我们的模型简单的一次线性变换。损失计算np.mean((y_pred - y) ** 2)对应MSE公式。梯度计算我们手动推导了MSE对w和b的偏导数并用NumPy实现了向量化计算。这是理解优化如何发生的核心。参数更新w w - learning_rate * dw这是梯度下降的实质。通过这个简单的例子你已经亲手实现了机器学习最核心的闭环预测 - 计算误差 - 根据误差调整模型。所有复杂的神经网络都是在这个基本环上叠加了更复杂的变换激活函数和更深的层次。4. 核心拆解二构建一个微型神经网络MLP理解了线性回归我们就可以组合多个这样的“线性变换非线性激活”构建一个真正的多层感知机MLP这是深度学习的基础单元。4.1 从单层到多层引入非线性单个线性回归器能力有限无法拟合复杂模式如异或问题。解决方案是堆叠多个线性层。在每个线性层后加入非线性激活函数如ReLU, Sigmoid这样网络就能拟合任意复杂的连续函数。一个最简单的两层MLP前向传播公式为h ReLU(X * W1 b1)y_pred h * W2 b2其中ReLU(x) max(0, x)。4.2 手写实现一个二分类MLP我们将实现一个具有一个隐藏层的MLP用于解决简单的二分类问题。import numpy as np import matplotlib.pyplot as plt from sklearn.datasets import make_moons from sklearn.model_selection import train_test_split # 1. 生成非线性可分数据月牙形 X, y make_moons(n_samples300, noise0.2, random_state42) y y.reshape(-1, 1) # 将标签变为列向量 X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.2, random_state42) # 2. 定义网络结构参数 input_size 2 # 输入特征数 (x1, x2) hidden_size 8 # 隐藏层神经元数量 output_size 1 # 输出层神经元数量 (二分类可以用一个神经元sigmoid) learning_rate 0.1 epochs 2000 # 3. 初始化参数使用He初始化适合ReLU def initialize_parameters(input_size, hidden_size, output_size): np.random.seed(1) W1 np.random.randn(input_size, hidden_size) * np.sqrt(2. / input_size) b1 np.zeros((1, hidden_size)) W2 np.random.randn(hidden_size, output_size) * np.sqrt(2. / hidden_size) b2 np.zeros((1, output_size)) return {W1: W1, b1: b1, W2: W2, b2: b2} params initialize_parameters(input_size, hidden_size, output_size) # 4. 定义激活函数及其导数 def relu(x): return np.maximum(0, x) def relu_derivative(x): return (x 0).astype(float) def sigmoid(x): return 1 / (1 np.exp(-x)) # 5. 前向传播 def forward_propagation(X, params): W1, b1, W2, b2 params[W1], params[b1], params[W2], params[b2] # 第一层: 线性变换 ReLU Z1 np.dot(X, W1) b1 A1 relu(Z1) # 第二层: 线性变换 Sigmoid (输出概率) Z2 np.dot(A1, W2) b2 A2 sigmoid(Z2) # A2就是预测概率 y_pred cache {Z1: Z1, A1: A1, Z2: Z2, A2: A2} return A2, cache # 6. 计算损失二元交叉熵 def compute_loss(y_pred, y_true): m y_true.shape[0] # 避免log(0)的情况进行数值稳定处理 loss -np.mean(y_true * np.log(y_pred 1e-8) (1 - y_true) * np.log(1 - y_pred 1e-8)) return loss # 7. 反向传播手动推导梯度 def backward_propagation(X, y_true, params, cache): m X.shape[0] W1, W2 params[W1], params[W2] A1, A2, Z1 cache[A1], cache[A2], cache[Z1] # 输出层梯度 dZ2 A2 - y_true # 这是SigmoidBCE损失求导后的简洁形式 dW2 (1 / m) * np.dot(A1.T, dZ2) db2 (1 / m) * np.sum(dZ2, axis0, keepdimsTrue) # 隐藏层梯度 dA1 np.dot(dZ2, W2.T) dZ1 dA1 * relu_derivative(Z1) # 链式法则乘以激活函数的导数 dW1 (1 / m) * np.dot(X.T, dZ1) db1 (1 / m) * np.sum(dZ1, axis0, keepdimsTrue) gradients {dW1: dW1, db1: db1, dW2: dW2, db2: db2} return gradients # 8. 更新参数 def update_parameters(params, gradients, learning_rate): params[W1] - learning_rate * gradients[dW1] params[b1] - learning_rate * gradients[db1] params[W2] - learning_rate * gradients[dW2] params[b2] - learning_rate * gradients[db2] return params # 9. 训练循环 train_losses [] test_losses [] for epoch in range(epochs): # 训练集前向传播和反向传播 y_pred_train, cache_train forward_propagation(X_train, params) loss_train compute_loss(y_pred_train, y_train) train_losses.append(loss_train) gradients backward_propagation(X_train, y_train, params, cache_train) params update_parameters(params, gradients, learning_rate) # 每隔一定轮次在测试集上评估 if epoch % 100 0: y_pred_test, _ forward_propagation(X_test, params) loss_test compute_loss(y_pred_test, y_test) test_losses.append(loss_test) if epoch % 500 0: print(fEpoch {epoch}: Train Loss {loss_train:.4f}, Test Loss {loss_test:.4f}) # 10. 评估与可视化 def predict(X, params): y_pred, _ forward_propagation(X, params) return (y_pred 0.5).astype(int) # 将概率转换为0/1类别 y_pred_train_final predict(X_train, params) y_pred_test_final predict(X_test, params) train_accuracy np.mean(y_pred_train_final y_train) test_accuracy np.mean(y_pred_test_final y_test) print(f\n训练准确率: {train_accuracy:.2%}) print(f测试准确率: {test_accuracy:.2%}) # 绘制决策边界 plt.figure(figsize(15, 5)) plt.subplot(1, 3, 1) plt.scatter(X_train[:, 0], X_train[:, 1], cy_train.flatten(), cmapcoolwarm, edgecolorsk) plt.title(Training Data) plt.xlabel(Feature 1) plt.ylabel(Feature 2) plt.subplot(1, 3, 2) # 生成网格点来绘制决策边界 h 0.02 x_min, x_max X[:, 0].min() - 0.5, X[:, 0].max() 0.5 y_min, y_max X[:, 1].min() - 0.5, X[:, 1].max() 0.5 xx, yy np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h)) Z predict(np.c_[xx.ravel(), yy.ravel()], params) Z Z.reshape(xx.shape) plt.contourf(xx, yy, Z, cmapcoolwarm, alpha0.8) plt.scatter(X_test[:, 0], X_test[:, 1], cy_test.flatten(), cmapcoolwarm, edgecolorsk, marker^) plt.title(fDecision Boundary (Test Acc: {test_accuracy:.2%})) plt.xlabel(Feature 1) plt.ylabel(Feature 2) plt.subplot(1, 3, 3) plt.plot(train_losses, labelTrain Loss) # 由于测试损失不是每轮都计算需要插值绘制 test_epochs np.arange(0, epochs, 100) plt.plot(test_epochs, test_losses, labelTest Loss, markero) plt.xlabel(Epoch) plt.ylabel(Loss (Binary Cross-Entropy)) plt.title(Training History) plt.legend() plt.grid(True) plt.tight_layout() plt.show()4.3 关键点解析参数初始化使用了He初始化 (np.sqrt(2. / input_size))这对ReLU激活函数更有效能缓解梯度消失/爆炸。激活函数隐藏层使用ReLU提供非线性输出层使用Sigmoid将输出压缩到(0,1)区间表示概率。损失函数使用二元交叉熵BCE这是二分类问题的标准损失。反向传播这是核心中的核心。代码中的dZ2 A2 - y_true是SigmoidBCE组合求导后的优雅结果。我们手动实现了链式法则将误差从输出层逐层反向传播到每一层的权重和偏置。决策边界通过可视化我们可以看到这个手写的MLP成功学习到了一个非线性的决策边界将两类数据分开。至此你已经不借助任何深度学习框架亲手实现并训练了一个能解决非线性分类问题的神经网络。你清晰地看到了数据如何流动前向误差如何反向传播并指导参数更新。5. 核心拆解三窥探Transformer架构的基石——Self-AttentionTransformer架构是当今大语言模型如GPT、BERT的基石而Self-Attention自注意力机制是其最核心的创新。让我们尝试拆解这个看似复杂的概念。5.1 Self-Attention的直觉理解想象你在阅读一句话“The animal didnt cross the street because it was too tired.” 这里的it指的是什么是animal还是street人类会自然地将it与animal关联起来。Self-Attention机制让模型具备这种能力它允许序列中的每个位置单词去“注意”序列中所有其他位置的信息并根据相关性动态地聚合信息。5.2 手写实现一个简易的Self-Attention我们忽略批量处理和多头机制实现一个最基础的、针对单个序列的Self-Attention。import numpy as np def softmax(x): 稳定的Softmax函数 exp_x np.exp(x - np.max(x, axis-1, keepdimsTrue)) # 减去最大值防止溢出 return exp_x / np.sum(exp_x, axis-1, keepdimsTrue) def scaled_dot_product_attention(Q, K, V, maskNone): 实现缩放点积注意力。 参数: Q: 查询矩阵 (seq_len, d_k) K: 键矩阵 (seq_len, d_k) V: 值矩阵 (seq_len, d_v) mask: 可选的掩码矩阵 (seq_len, seq_len) 返回: output: 注意力加权后的输出 (seq_len, d_v) attention_weights: 注意力权重 (seq_len, seq_len) d_k Q.shape[-1] # 1. 计算Q和K的点积 scores np.dot(Q, K.T) # (seq_len, seq_len) # 2. 缩放 scores scores / np.sqrt(d_k) # 3. 可选应用掩码如解码器的掩码防止看到未来信息 if mask is not None: scores scores mask * -1e9 # 将掩码位置设为负无穷softmax后接近0 # 4. 应用Softmax得到注意力权重 attention_weights softmax(scores) # (seq_len, seq_len) # 5. 权重乘以V得到最终输出 output np.dot(attention_weights, V) # (seq_len, d_v) return output, attention_weights # 让我们用一个极简的例子来演示 # 假设我们有一个包含3个单词的序列每个单词用4维向量表示嵌入维度d_model4 np.random.seed(0) seq_len 3 d_model 4 # 随机生成输入序列 X (3个单词每个单词4维向量) X np.random.randn(seq_len, d_model) print(输入序列 X (shape: {}):\n{}.format(X.shape, X)) # 在标准Transformer中Q, K, V是通过线性变换从X得到的。 # 为了简化我们假设权重矩阵W_Q, W_K, W_V是单位矩阵即 QKVX。 # 在实际中它们是不同的可学习参数。 W_Q np.eye(d_model) # 简化为单位矩阵 W_K np.eye(d_model) W_V np.eye(d_model) Q np.dot(X, W_Q) K np.dot(X, W_K) V np.dot(X, W_V) print(\n查询矩阵 Q (shape: {}):\n{}.format(Q.shape, Q)) print(\n键矩阵 K (shape: {}):\n{}.format(K.shape, K)) print(\n值矩阵 V (shape: {}):\n{}.format(V.shape, V)) # 计算自注意力 output, attn_weights scaled_dot_product_attention(Q, K, V) print(\n注意力权重矩阵 (shape: {}):.format(attn_weights.shape)) print(attn_weights) print(\n每个单词的注意力输出 (shape: {}):.format(output.shape)) print(output) # 解释注意力权重矩阵的第i行表示第i个单词对所有单词包括自己的注意力分数。 # 输出矩阵的第i行是第i个单词根据注意力权重对V值的加权和即它“注意”到的信息。 print(\n--- 解读 ---) print(f对于单词0X[0]它对单词0、1、2的注意力分数分别为{attn_weights[0]}) print(f因此单词0的新表示output[0]是) print(f {attn_weights[0][0]:.2f} * V[0] {attn_weights[0][1]:.2f} * V[1] {attn_weights[0][2]:.2f} * V[2]) print(f 最终结果{output[0]})5.3 从Self-Attention到Transformer上面的代码展示了最核心的注意力计算。在一个完整的Transformer中多头注意力Multi-Head Attention将d_model维的Q、K、V投影到多个如8个低维子空间d_k,d_v在每个头上并行计算注意力最后将结果拼接并投影。这允许模型同时关注来自不同表示子空间的信息。位置编码Positional EncodingSelf-Attention本身没有顺序信息需要向输入嵌入中加入位置编码。前馈网络Feed-Forward Network对注意力输出进行非线性变换。残差连接与层归一化Add Norm为了训练更深的网络每个子层注意力、前馈都包裹着残差连接和层归一化。通过手写Self-Attention你理解了Transformer如何让模型动态地、有选择地聚焦于输入序列的不同部分这是其强大上下文理解能力的根源。6. 常见问题与手写实践中的坑点在亲手实现这些算法的过程中你一定会遇到各种问题。以下是典型问题及解决思路问题现象可能原因解决思路梯度爆炸或消失Loss变成NaN或无限大1. 学习率过大。2. 参数初始化不当如权重全为0或过大。3. 网络层数过深没有使用归一化。1. 降低学习率如从0.1调到0.01。2. 使用合适的初始化Xavier/He初始化。3. 在深层网络中引入BatchNorm或LayerNorm。模型不收敛Loss居高不下或震荡1. 学习率可能不适宜太大或太小。2. 数据未归一化/标准化。3. 损失函数或梯度计算有误Bug。4. 模型容量不足过于简单。1. 尝试学习率衰减或使用自适应优化器如Adam的思路。2. 对输入特征进行标准化减均值除方差。3.核心检查点用数值梯度检验Gradient Checking验证手写梯度是否正确。这是手写实现时必须做的4. 增加网络宽度或深度。过拟合训练集Loss小测试集Loss大模型过于复杂记住了训练数据噪声。1. 增加训练数据。2. 使用正则化L1/L2在损失中加入权重惩罚项。3. 使用Dropout随机丢弃一部分神经元。4. 早停Early Stopping。数值不稳定如Softmax溢出指数函数exp(x)在x较大时极易溢出。实现数值稳定的Softmaxsoftmax(x) exp(x - max(x)) / sum(exp(x - max(x)))。确保在计算前减去最大值。Self-Attention权重矩阵对角线值特别高在简化示例中QKV导致每个单词与自己的点积自相关最大。这是正常现象。在实际Transformer中Q、K、V由不同的可学习权重矩阵生成模型会学习到更有意义的注意力模式。梯度检验示例这是验证你手写的反向传播是否正确的最可靠方法。def gradient_checking(X, y, params, forward_prop, compute_loss, epsilon1e-7): 数值梯度检验。 通过微扰参数计算损失的近似梯度与反向传播计算的梯度进行比较。 # 将参数字典展平为一个向量 param_vector, shapes, keys _flatten_params(params) grad_vector _flatten_grads(backward_propagation(X, y, params, forward_prop(X, params)[1]))[0] num_grads np.zeros_like(param_vector) for i in range(len(param_vector)): # 创建参数向量的副本并对第i个元素施加微小扰动 theta_plus np.copy(param_vector) theta_minus np.copy(param_vector) theta_plus[i] epsilon theta_minus[i] - epsilon # 将扰动后的向量恢复为参数字典 params_plus _restore_params(theta_plus, shapes, keys) params_minus _restore_params(theta_minus, shapes, keys) # 计算扰动后的损失 loss_plus compute_loss(forward_prop(X, params_plus)[0], y) loss_minus compute_loss(forward_prop(X, params_minus)[0], y) # 数值梯度近似 num_grads[i] (loss_plus - loss_minus) / (2 * epsilon) # 计算反向传播梯度和数值梯度的差异 diff np.linalg.norm(grad_vector - num_grads) / (np.linalg.norm(grad_vector) np.linalg.norm(num_grads)) print(f梯度检验差异度: {diff}) if diff 1e-7: print(✅ 反向传播实现正确) else: print(❌ 反向传播可能有误请检查代码。) return diff # 注意_flatten_params, _restore_params 等辅助函数需要根据你的参数结构实现。7. 最佳实践与工程化思考将“手写”的洞见迁移到工程实践中能极大提升你的AI开发能力。从理解到调试当你用PyTorch训练一个复杂模型出现问题时如果你亲手实现过反向传播你会本能地去检查梯度流model.parameters()的grad属性怀疑是某一层的激活函数饱和了而不是盲目地调整学习率。自定义层和损失函数框架提供的层和损失函数并非万能。当你有特殊需求时如一个新的注意力变体、一个领域特定的损失函数手写的经验让你能自信地继承nn.Module或Function类实现自定义模块。模型轻量化与部署理解每个操作的数学本质有助于你在模型部署时进行有效的融合、量化和剪枝。你知道哪些操作是计算密集型的如大矩阵乘法哪些是内存访问密集型的。阅读论文与复现当一篇AI论文提出一个新架构时你能快速抓住其核心创新点是提出了新的注意力计算方式是改进了优化算法还是设计了新的模块连接方式你能将其核心公式翻译成可运行的代码。构建个人知识体系将手写实现的代码、公式推导、问题笔记整理成你自己的“AI构建手册”。这比收藏无数篇博客文章更有价值。8. 总结与学习路线建议Prof. Tom Yeh的“亲手打造的AI”专栏精神其价值远超过学会几个模型。它培养的是一种第一性原理的思考方式和拆解复杂系统的能力。建议的学习路线夯实基础从线性回归、逻辑回归开始彻底弄懂损失函数、梯度下降。深入神经网络实现一个全连接MLP理解前向/反向传播、激活函数、初始化。征服CNN手写卷积、池化操作理解局部连接、权值共享、特征图。理解RNN/LSTM实现时间步循环理解隐藏状态和梯度在时间上的传播。拆解Transformer实现Self-Attention、多头注意力、位置编码并尝试组合成一个Decoder-Only或Encoder-Decoder小模型。探索优化算法实现SGD、Momentum、Adam比较其收敛特性。转向现代框架在有了深厚的手写基础后再用PyTorch/TensorFlow去实现相同的模型。此时框架的API对你而言将是透明的你关注的是如何更高效、更优雅地组织代码。记住目标不是永远手写而是通过手写获得深刻理解从而更自信、更高效地使用高级工具并具备创造新工具的能力。下次当你面对一个复杂的AI系统时试着问自己“如果让我从零开始我能否勾勒出它的核心骨架” 这就是“亲手打造的AI”带给你的终极礼物。
返回列表