简介:《AI培训:1-AI初体验-人工智能通识基础课》是一套面向零基础学习者的人工智能入门讲义,围绕AI基本概念、发展脉络与大数据背景下的实际应用展开,帮助读者建立通识框架并衔接后续学习。内容从达特茅斯会议与符号主义、连接主义讲起,延伸到机器学习、自然语言处理、计算机视觉和机器人技术等核心分支,同时涉及数据预处理、特征工程及Hadoop、Spark等平台在AI项目中的角色,并讨论隐私、就业与算法歧视等伦理议题。压缩包内为1个PDF文件,约6.25MB,便于集中阅读和随时查阅。已有385人学习,适合希望用较短时间梳理AI知识地图、理解典型应用并形成伦理意识的初学者。
1. 从一个「训练集 99%、线上 62%」的落差说起
一个模型在训练集上准确率 99%,上线一周掉到 62%。这不是段子,是几乎每个刚接触人工智能项目的团队都会撞上的第一堵墙,而且它跟算力、跟框架版本都没关系——问题出在整条链路的某一环被悄悄破坏了。大多数人学 AI 的顺序是反的:先去调包跑通一个模型,再回头补概念,最后才发现自己根本说不清「数据是怎么进来的」。这份人工智能通识基础课的价值不在于教你调某个库,而在于把从概念、范式、大数据管道到伦理边界这条链路一次铺开,让你在动手之前就知道哪一步会塌。搞懂它,你才有判断一个 AI 需求该不该接、能不能落地的底气,而不是被人一句「上个大模型」牵着走。
2. 从规则到表示学习:为什么「把知识写进 if-else」的成本会指数爆炸
人工智能早期的路子非常朴素:人怎么想,就把这个过程翻译成规则。符号主义那一代研究者相信,智能的本质是对符号的运算,只要把世界拆成实体和关系,再写足够多的推理规则,机器就能表现出智能。这个信念在实验室里成立,在工业界撞了墙,墙的名字叫「知识获取瓶颈」。搞懂这个瓶颈,你才能明白后面所有技术选择为什么长成现在这个样子。
2.1 知识获取瓶颈:规则系统的成本曲线长什么样
规则系统的成本不是线性的。假设你做一个工单自动分类器,一开始 200 条关键词规则能覆盖 80% 的工单,看起来很美。等你要把覆盖率从 80% 推到 95%,得再写 2000 条规则;从 95% 推到 98%,可能还要 5000 条,而且每加一条新规则,都要回头检查它会不会和已有规则冲突。规则之间的交互是组合式的,N 条规则的潜在冲突面接近 N²,维护成本随规模平方增长,而收益是线性甚至次线性的。
更麻烦的是「边界情况」。规则是人根据经验写的,人写规则时脑子里想的是典型案例,而真实数据里长尾部分永远比你预想的多。一个做票据识别的团队曾统计过,他们前 300 条规则处理了标准票据,后面 3000 条规则全在处理「盖章位置偏了」「手写体潦草」「扫描件有折痕」这类边角料。规则越写越像在给数据打补丁,而不是在描述规律。
这就是「知识获取瓶颈」的真实含义:知识明明存在专家脑子里,但要把它转成机器能执行的符号,中间那道人工翻译的成本高到不可持续。专家会老、会走,规则文档会腐烂,最后没人敢动那个文件。血泪经验是,凡是需要三个人以上长期维护的规则库,基本都已经在失控边缘。
2.2 表示学习替换掉的到底是哪一层人力
连接主义换了个思路:不告诉机器「怎么判断」,只给机器「判断得对不对」,让它自己去找中间表示。这一换,换掉的正是那道人工翻译工序。原始像素、原始文本、原始点击日志直接喂进去,模型内部自己长出「边缘」「纹理」「词组合」这类中间概念。这些概念没有名字,你也没法用一句话描述它们,但它们确实把原始输入搬到了一个更容易做线性划分的空间里。
下面这段代码是一个最小可训练单元,它没有任何业务规则,全部参数都从数据里长出来:
import numpy as np # 一个最小可训练单元:h = relu(xW1 + b1),logits = hW2 + b2 # 注意:W 不是人写的规则,而是训练过程中被数据"推"出来的 rng = np.random.default_rng(42) D_IN, D_HID, D_OUT = 784, 128, 10 # He 初始化:方差按 fan_in 缩放,避免深层网络激活值逐层塌缩 W1 = rng.normal(0, np.sqrt(2.0 / D_IN), size=(D_IN, D_HID)) b1 = np.zeros(D_HID) W2 = rng.normal(0, np.sqrt(2.0 / D_HID), size=(D_HID, D_OUT)) b2 = np.zeros(D_OUT) def forward(x): h = np.maximum(0.0, x @ W1 + b1) # 隐层:把 784 维像素搬到 128 维新空间 logits = h @ W2 + b2 # 输出层:在新空间里做线性划分 return h, logits params = W1.size + b1.size + W2.size + b2.size print(params) # 101770,约 10 万个可调数字参数量算下来是 784×128 + 128 + 128×10 + 10 = 101770。这 10 万个数字没有任何一个对应「如果有『发票』二字则加分」这样的语义,它们是一组让损失函数下降的数值解。np.sqrt(2.0 / D_IN)里的 2 来自 ReLU 把一半激活值置零、方差减半这一事实,除数fan_in是输入维度——这是为了让每一层的输出方差大致稳定,否则堆到十几层时前向信号会趋近于零,反向梯度会趋近于无穷,训练直接崩。
np.maximum(0, ...)这一行看起来无害,它才是「表示学习」能成立的关键。没有非线性,两层线性叠起来还是线性,等价于一层,堆多深都没用。有了 ReLU,网络才有能力把输入空间折叠成任意形状,隐层的那 128 个数字才真正成为一组「学出来的特征」,替代掉原本要人手写的特征模板。
2.3 三代范式的真实关系是叠加,不是替代
很多人学完历史沿革会产生一个错觉:符号主义被连接主义淘汰了。实际情况是三层技术叠在一起,各自守着自己的地盘。符号系统擅长的是「规则明确、可审计、不能出错」的场景——审批流、额度计算、合规校验,这些地方你必须要有一个能打印出来给人看的判定依据,神经网络的概率输出在这里反而是缺陷。
统计学习那一层夹在中间,它不追求理解语义,只追求在特征空间里找到一条分界线。风控里的评分卡模型就是典型:特征是人挑的、可解释的,模型只负责加权。深度学习的出现没有让评分卡消失,因为业务方需要知道「为什么拒绝这笔申请」,而一个 128 维隐层给不出这个答案。
所以判断一个需求该不该上模型,有个很土但好用的标准:这个问题你能不能用三句话把判定规则写清楚?能,就写规则,别上模型;不能,但你手上有大量「输入-正确答案」的样本,那就是监督学习的地盘;既说不清规则又没有样本,那才是真正麻烦的情况,通常得先想办法把数据攒出来。这条判断线,比任何算法选型表都实用。
3. 三类范式的分水岭:监督、无监督、强化学习的「反馈信号」从哪来
机器学习被切成监督、无监督、强化三块,教科书通常按「有没有标签」来分。这个分法没错,但不够本质。真正的分水岭是:你用来指导模型改进的那个「反馈信号」是从哪来的,它的信息量有多大,它的噪声有多大。搞清这一点,你就能预判一个任务大概能做成什么样。
3.1 监督学习:损失函数其实是「答案的距离函数」
监督学习的信息量最足,因为每个样本都带着标准答案。模型输出一个预测,损失函数计算它和答案之间的距离,反向传播把这个距离翻译成每个参数的调整方向。整个训练过程就是在参数空间里沿着梯度的反方向往下走。
分类任务最常用的损失是交叉熵,它和 softmax 绑在一起用是有原因的:
import numpy as np def softmax(logits): # 减去最大值只为数值稳定,数学上等价,不改变输出分布 z = logits - logits.max(axis=-1, keepdims=True) e = np.exp(z) return e / e.sum(axis=-1, keepdims=True) logits = np.array([2.0, 1.0, 0.1]) y_true = 0 # 正确类别是第 0 类 p = softmax(logits) # [0.6590, 0.2424, 0.0986] loss = -np.log(p[y_true]) # 0.4170 grad = p.copy() grad[y_true] -= 1.0 # dL/dlogits = softmax 输出 - onehot 标签 print(p, loss, grad) # grad = [-0.3410, 0.2424, 0.0986]关键在最后两行。交叉熵对 logits 的梯度恰好等于「预测概率减真实标签」,形式极其干净:预测偏高的类别得到负梯度(往下压),偏低的类别得到正梯度(往上抬),梯度大小自动正比于预测错得有多离谱。这就是为什么分类任务几乎不用均方误差——均方误差经过 softmax 后梯度里会多出一个p(1-p)因子,当模型错得很自信时这个因子接近 0,梯度反而消失,学不动。
-np.log(p[y_true])这一项还有个细节:如果预测概率真的到了 0,log 会变成负无穷。工程上没人直接这么写,都是把 softmax 和交叉熵合成一个算子做数值稳定,或者给概率加一个极小的 epsilon。这是新手最常翻的车之一,训练到一半 loss 变nan,八成是在这里。
监督学习的软肋是标签本身。标签是人标的,人会有分歧、会累、会按自己的理解偏。一个团队花三个月把准确率从 91% 调到 93%,最后发现标注一致性只有 88%——上限早就被标注质量锁死了,后面的调优全是在拟合标注噪声。
3.2 无监督学习:没有标签时,优化目标是谁定的
无监督学习常被误解成「没有目标」,其实它有目标,只是目标不是人给的答案,而是人从数据结构里假设出来的某种「好」。聚类假设「好的划分是簇内紧凑、簇间分离」,降维假设「好的表示是丢掉的维度信息最少」,自监督假设「被遮住的部分可以从上下文推回来」。这些假设对不对,没有人告诉你。
这就是无监督最难受的地方:优化目标是你自己定的,所以效果好不好也得你自己判断,没有一个客观的 ground truth 兜底。KMeans 是最典型的例子,它最小化簇内平方和,但聚类数 k 必须人来指定。你给 k=5,它就会把数据切成 5 块,哪怕数据本来有 12 个自然簇。它不会报错,不会警告,只会给你一个看起来挺整齐的结果。
常见的应对思路是换评估维度:轮廓系数、簇的稳定性(换随机种子重跑看结果是否一致)、以及最土但最有效的一招——把簇心拿出来给业务方看,问一句「这五类说得通吗」。业务不认可的聚类,数学指标再漂亮也没用。
自监督是这几年最值得关注的方向,它的巧妙之处在于从数据本身造标签:遮住句子里一个词让模型猜,把同一张图做两种增强让模型判断是不是同源。这样既有监督学习那样明确的损失函数,又不需要人工标注。这条路子把「无监督没有客观目标」的问题绕过去了,代价是造出来的任务和真实任务之间存在偏差,预训练学到的东西未必都对下游有用。
3.3 强化学习:延迟回报下的信用分配
强化学习的信息形态和前两者完全不同。它既没有标准答案,也没有数据结构假设,只有一个标量奖励,而且这个奖励往往是延迟的——下围棋要走完 200 手才知道输赢,推荐系统要用户停留十分钟才知道这次推得好不好。
延迟回报带来两个硬问题。第一个是信用分配:最终赢了,到底是第 37 手那步妙棋的功劳,还是第 180 手对手失误送的?常见的做法是引入折扣因子 γ,把未来奖励按 γ^t 折现回当前时刻,越远的奖励权重越小。γ=0.99 意味着 100 步之后的奖励只剩三分之一的影响力,这个数怎么定,直接决定了模型是短视还是远视。
第二个是探索与利用的权衡。模型当前认为最优的动作未必真的最优,如果一直选它,就永远发现不了更好的选择;如果一直乱试,又积累不了有效经验。这个问题在监督学习里根本不存在,因为答案已经摆在那里了,你只需要逼近它。
强化学习在通识课里通常只讲概念不讲实现,原因很实际:样本效率太低。一个监督学习任务几千条样本能出效果,同样的问题用强化学习可能要几百万次交互,而且训练曲线抖动剧烈,换个随机种子结果能差一倍。所以真实项目里的顺序一般是:能用监督学习解决就别碰强化学习,实在没有标注数据、又必须做序列决策时,才考虑它。
| 维度 | 监督学习 | 无监督学习 | 强化学习 |
|---|---|---|---|
| 反馈信号 | 每条样本的标准答案 | 人为构造的结构假设 | 环境返回的标量奖励 |
| 典型损失 | 交叉熵、均方误差 | 簇内平方和、重构误差 | 策略梯度、时序差分误差 |
| 评估难度 | 低,有客观指标 | 高,需业务确认 | 高,方差大且依赖环境 |
| 主要失败模式 | 标签噪声、数据泄漏 | 假设不成立、k 值拍脑袋 | 样本效率低、奖励设计错误 |
4. 大数据管道:为什么迭代训练受不了「落盘」,以及特征工程为什么会泄漏
模型只是整条链路的最后一环。真实项目里,从原始日志到能喂进模型的特征矩阵,中间那段管道决定了效果的上限。这一段最容易被初学者忽略,也最容易出那种「代码没报错、结果就是不对」的隐性问题。
4.1 预处理与特征工程:模型效果的大头在进入模型之前
原始数据几乎不能直接用。缺失值要处理(删、填均值、填中位数、还是单独标记成一个类别,每种选择都在向模型注入假设),类别变量要编码(独热编码在基数上万时会炸成几万列稀疏矩阵,目标编码又极易泄漏),连续值要缩放(不同量纲的特征会让梯度下降走成之字形,收敛慢十倍)。
量纲这件事值得单独说。一个特征范围是 0 到 1,另一个是 0 到 1000000,梯度对前者几乎是平的、对后者极其陡峭,学习率没法同时适配。标准化(减均值除标准差)和归一化(缩到 [0,1])解决的就是这个问题,让所有维度在同一个尺度上被平等对待。
但缩放有个前提条件经常被违反:统计量只能来自训练集。下面的写法看着很自然,其实是错的:
import pandas as pd train = df.iloc[:8000].copy() test = df.iloc[8000:].copy() # 错误:均值和标准差用到了 test 的信息,测试集不再是"没见过的数据" mu_all, sd_all = df["amount"].mean(), df["amount"].std() # 正确:统计量只从 train 计算,然后用同一组参数变换 test mu, sd = train["amount"].mean(), train["amount"].std() train["amount_z"] = (train["amount"] - mu) / sd test["amount_z"] = (test["amount"] - mu) / sd # 注意:用的是 train 的 mu/sd差别在哪?用全量统计量时,测试集的分布信息提前渗进了训练过程,模型在离线评估里表现会虚高一点点。连续特征上这个偏差通常很小,所以它不显眼;但换成目标编码(用标签均值替换类别)就是灾难级的——每个类别的编码值里都掺进了测试样本的标签,离线 AUC 能冲到 0.99,上线立刻打回原形。
更隐蔽的是时间维度。用随机切分做时间序列的 train/test,等于让模型用未来的数据预测过去。正确做法是按时间点切:用前 8 个月训,后 2 个月测。这一条在风控、销量预测、推荐里都是铁律,违反了模型学到的全是「未来信息」。
4.2 从磁盘屏障到 DAG 内存复用:分布式计算范式换了什么
数据量超过单机内存时,就得靠分布式。第一代方案的思路很清晰:把计算拆成 map 和 reduce 两个阶段,中间结果落盘,靠磁盘扛住数据量。这套模型皮实、容错简单,但有个致命伤——每一次计算都要读盘、写盘。
机器学习训练恰恰是迭代式的。梯度下降要跑几百轮,每轮都要把全量数据过一遍。如果每轮都是一个独立的批处理作业,那就意味着几百次「读盘→算→写盘→再读盘」。磁盘 IO 和网络传输成了绝对瓶颈,CPU 大部分时间在等数据。有人测过,在这种范式下做迭代计算,真正的计算时间占比可能不到 10%。
第二代方案改的是执行计划。它把整个计算表达成一张有向无环图,多个算子能连续执行的就连成一个阶段,中间结果留在内存里直接喂给下一个算子,只在必须跨节点重分区的边界上才落盘。注意,不是「不落盘」,而是把落盘次数从「每个算子一次」压到「每次重分区一次」。
容错机制也跟着换了。既然中间结果不落盘,机器挂了怎么恢复?答案是记录血缘:每个数据集记住自己是由哪个数据集经过什么算子算出来的,丢了就按血缘重算那一部分。代价是重算,收益是平时不用付落盘的代价。这个取舍很典型——用计算换 IO。
| 维度 | 批处理落盘范式 | DAG 内存计算范式 |
|---|---|---|
| 中间结果 | 每个阶段写磁盘 | 尽量留在内存,仅在重分区时落盘 |
| 迭代任务 | 每轮一个独立作业,IO 开销巨大 | 多轮共享同一批缓存数据 |
| 容错方式 | 失败重跑整个作业 | 按血缘关系重算丢失分区 |
| 适用场景 | 一次性离线清洗、超大冷数据 | 迭代训练、交互式分析、多步管道 |
理解了这一层,「为什么有些框架做迭代快、有些做批处理稳」就不再是玄学,而是执行计划里落盘次数的差异。选型时问一句「这个任务要迭代多少轮、数据能不能塞进内存」,答案基本就出来了。
4.3 特征泄漏:最隐蔽也最致命的一类错误
前面提了统计量泄漏和时间泄漏,还有一类更狡猾的:特征本身在预测发生的那一刻根本拿不到。比如预测用户会不会下单,你用上了「本次会话的最终成交金额」——这个字段在预测时点是不存在的,但它和标签高度相关,模型会死死抓住它,离线指标漂亮得不像话。
排查这类问题的办法很笨但很有效:把每个特征拿出来问一句「这条记录产生的那一秒,这个值算出来了吗」。答不上来的,一律先剔除。另一个办法是看特征重要性排名,如果某个特征的重要性高得离谱(比如单特征 AUC 就 0.9),先怀疑泄漏,别急着庆祝。
5. 常见问题与排查:五个把「通识」学成「玄学」的坑
通识基础课讲完概念,真正的考验在动手。下面这几条是初学者最容易踩的,几乎每一条我都见过有人在同一个地方反复翻车。按「现象 → 原因 → 解决」记下来,比背公式管用。
5.1 效果类故障:训练集好看、线上难看
现象:训练集准确率 99%,验证集 97%,上线一周掉到 62%,而且随着时间推移还在往下掉。
原因:三种可能,按概率排序。第一是数据泄漏,验证集和训练集之间存在信息渗透,前面讲的统计量泄漏、时间泄漏都算。第二是分布漂移,线上数据的分布和训练时不一样,比如训练数据来自某几个渠道,上线后全渠道流量涌入。第三是评估口径不一致,离线算的是「所有样本的平均准确率」,线上业务方看的是「高价值用户里的准确率」,两个数根本不是一回事。
解决:先做时间切分的验证,用最近一个月的数据当测试集,看指标掉多少;再逐个特征排查泄漏;最后和业务方对齐评估口径,把线上真正关心的那一小撮样本单独算指标。三件事做完,通常能定位到具体是哪一环。
5.2 工程类故障:loss 不降、loss 变 nan、显存爆掉
现象:训练跑了十轮,loss 在 2.3 附近纹丝不动,或者第二轮直接变成nan。
原因:loss 不动的头号原因是学习率。太大,参数在最优解附近来回横跳,loss 剧烈震荡;太小,十轮走不出初始化那一片平地。第二号原因是标签错位——特征和标签没对齐,模型在学随机噪声,这种情况下 loss 会稳定在一个接近随机猜测的值上(二分类约 0.693)。变成nan则多半是数值问题:log(0)、除零、梯度爆炸。
解决:先跑一个极小数据集(比如 32 条样本)过拟合看看,如果连 32 条都拟合不了,说明代码有 bug 而不是调参问题。然后打印第一批数据的特征和标签,人工核对是否对应。学习率从 1e-3 开始按 3 倍网格搜,观察前 100 步的 loss 曲线形状。加梯度裁剪防爆炸,softmax 前减最大值防溢出。
现象(显存):把 batch size 调到 256 就 OOM,调到 32 又抖得厉害。
原因:显存占用大致正比于 batch size 乘以单样本的激活值,而激活值和模型深度、序列长度都相关。参数本身占的显存反而是小头。
解决:用梯度累积——batch 设 32,连跑 8 次把梯度累加起来再更新一次,等效 batch 是 256,显存只按 32 算。再配合混合精度,显存还能再省一半。这两招基本能让你在小显存上跑出大 batch 的效果。
5.3 合规类故障:把不该进模型的东西喂进去
现象:模型效果很好,但上线评审被卡住,或者上线后收到用户投诉。
原因:特征里混进了敏感属性(性别、年龄、地域等),模型可能学出歧视性的决策路径;或者训练数据里含有未脱敏的个人信息,模型把它记住了。这类问题的特点是不会在指标上暴露,只会在合规审查或用户反馈时爆出来。
解决:建模前先做特征清单评审,把每个字段的合规属性标出来;训练数据入湖前做脱敏;上线前跑一遍公平性评估,看不同群体的通过率差异是否在可接受范围内。通识课里专门讲 AI 伦理不是凑数,它是唯一一类「技术指标全绿但项目直接死掉」的风险。
提示:排查顺序永远是「数据 → 特征 → 切分 → 模型 → 超参」,从上游往下游查。反过来查,你会在调参上浪费掉 80% 的时间。
6. 取舍的边界:为什么入门阶段先学「不做什么」
通识课有个绕不开的取舍:是先把数学推导讲透,还是先把边界和失败模式讲清。前者严谨,但初学者在还不会用工具的时候就被矩阵求导劝退;后者实用,代价是学员暂时说不清反向传播的链式法则细节。这门课选了后者,我认为这个选择是对的——入门阶段最大的成本不是「不会算」,而是「用错工具还浑然不觉」。
判断自己有没有真的学进去,可以用三个问题自测:给你一个业务需求,你能不能说出它属于哪类范式、需要什么样的反馈信号;给你一份数据,你能不能判断哪些字段在预测时点拿不到;给你一个 99% 的离线指标,你的第一反应是庆祝还是怀疑泄漏。三个问题都答得上来,说明底层认知已经建起来了,剩下的调参和工程细节都是时间问题。
至于进阶方向,我的建议是先往「数据」走而不是往「模型」走。把特征工程、数据切分、评估口径这三件事做扎实,收益远大于换一个更先进的网络结构。真实项目里模型结构的差异往往只有一两个点,而数据管道的一个泄漏能让指标虚高三十个点。
早年我在一个模拟项目里带过一个组,为了把离线指标刷到 0.95 连熬了两周,换模型、调超参、加特征,最后发现是目标编码时用了全量标签,指标是假的。删掉那个特征之后,模型的真实水平只有 0.78,而这两周里没有一个人想过去核对一下切分逻辑。从那以后我每次拿到一份漂亮得不像话的离线结果,都强制先跑一遍「这个特征在预测时点拿得到吗」的清单,一个字段一个字段过,过完才允许自己高兴。希望帮到你。
本文还有配套的精品资源,点击获取