大厂开源AI入门课程:Notebook实战神经网络与图像文本处理
简介:微软 AI-For-Beginners(中文版)是一套面向零基础学习者、转行开发者与教学者的系统人工智能入门课程包,按12周24课的教学大纲编排,从符号人工智能的知识表示与推理讲起,延伸至神经网络与深度学习、计算机视觉、自然语言处理,并涉及遗传算法、多智能体系统等较少见的方法,每课配有练习代码与测验。包内共375个文件,以101张png与17张jpg图示、80个md课程讲义、53个ipynb交互式Notebook为主体,另有32个json配置、9个py脚本、4个vue与4个html页面及少量mp4演示视频,压缩包约56.7MB,目录按课程模块分层组织,便于逐课跟练。已有140人学习下载。深度学习部分用TensorFlow与PyTorch双框架示例对照讲解,Notebook可直接运行调试,配合讲义中的实验活动能边学边验证;道德AI原则、训练技巧等内容另设独立章节,适合作为自学路线或课堂教学参考。
1. 卡在“看得懂却写不出”的那道坎上
学 AI 最难受的阶段,不是公式看不懂,而是视频看完、推导也跟上了,打开编辑器却连一个能跑起来的训练循环都写不出来。这份大厂开源、带中文翻译和配套练习代码的 AI 入门课程,就是用来衔接这段断层的:每一讲都配一份可执行的 Notebook,概念讲完立刻给一个能跑的最小实验,从符号推理、神经网络基础,一路铺到图像分类和文本处理的实战模型。
它的定位既不是论文导读,也不是调包速成课。课程重心放在“这条链路为什么这么设计”上,因此对想建立完整认知的人价值最大。适合会一点 Python、想动手复现的在校生和转岗开发者,也适合培训讲师拿它当课件底稿。
接下来按“课程骨架 → 核心代码 → 怎么跑起来 → 常见问题 → 二次开发”的顺序拆。中间几段代码都是从课程练习里抽出来的最小骨架,可以直接抄进自己的实验目录。
2. 课程骨架拆解:一份讲义、一份 Notebook、一份作业的组合结构
先说清这套资源是什么形态。它不是一本 PDF 教材,也不是一堆散装的 ipynb,而是一个按主题分单元的仓库型课程:每个单元一个目录,目录里通常三件套,讲义 README、课堂演示 notebook、课后作业 notebook,部分单元再带一份参考答案。
这套三件套的结构决定了你怎么用它,也直接决定后面会遇到哪些问题。讲义负责讲“为什么”,演示 notebook 负责讲“长什么样”,作业 notebook 负责让你自己写一遍。我见过太多人只读讲义不跑 notebook,结果一周后忘干净;也见过只跑不改的,跑完还是不会自己搭。
2.1 目录结构:拿到仓库先看这四层
不用急着装环境,先花十分钟把目录扫一遍,心里有张地图,后面找数据和改代码会省很多时间。我拿到手的中文版大致是下面这个结构:
ai-course-zh/ ├── lessons/ │ ├── 01-intro-and-history/ │ │ ├── README.md # 讲义正文(中文译文) │ │ ├── notebook.ipynb # 课堂演示,边讲边跑 │ │ └── assignment.ipynb # 课后作业,留空待填 │ ├── 02-symbolic-ai/ # 专家系统、知识表示 │ ├── 03-neural-networks/ # 感知机、多层网络、训练技巧 │ ├── 04-computer-vision/ # 卷积、迁移学习、检测与分割 │ ├── 05-nlp/ # 文本预处理、词袋、词向量、序列模型 │ └── 06-ethics-and-frontier/ # 伦理、强化学习、生成模型概览 ├── translations/ # 各语种译文,中文版主要改这里 ├── requirements.txt # 全课程依赖,注意它不一定锁版本 └── data/ # 小数据集;大数据集运行时下载看这个结构有几个点值得注意。第一,lessons下每个目录相互独立,你完全可以只跑第四章的图像部分,不用管前面几章,这对时间碎片化的人很友好。第二,translations目录说明中文版主要是译文层的改动,notebook 里的代码基本保持原样,所以中文版一样会遇到英文课程里的环境问题,只是讲义好读了。第三,requirements.txt往往只写包名不锁版本,这是后面踩坑的高发区,我在第 5 章会专门讲。
如果你想按周排学习计划,我的建议是按目录顺序走,但把 02 符号 AI 那段当成选学内容。它对你理解后面的神经网络没有直接帮助,但对理解“专家系统为什么会退潮”很有价值,讲课时是很好的铺垫材料。
2.2 技术栈选型:Jupyter 加双框架的取舍
这套课程的技术栈非常“教学友好”:Python 3 + Jupyter Notebook 作为载体,深度学习部分同时给了两套实现,一套基于 Keras/TensorFlow,一套基于 PyTorch,配套还有 scikit-learn、matplotlib、NumPy,图像部分会用 OpenCV,文本部分会用到分词和向量化工具。
为什么用 Notebook 而不是普通 .py 脚本?因为教学场景需要图文同屏。一张卷积核滑过特征图的示意图,紧跟一段能打印出中间张量形状的代码,这个组合用脚本很难做到。Notebook 还有个隐性好处:输出单元格会保留,你跑完一次之后,即使忘了细节,翻回去还能看到当时的结果。
代价也很明确:Notebook 有隐含状态。单元格可以跳着执行,变量可以带着上一次的残留值继续跑,所以你看到的结果不一定是“从零开始”的结果。这是新手最容易产生的误解:明明代码一模一样,为什么我跑出来的准确率和你不一样?大概率是你上面的某个单元格没执行,或者执行了两遍。
至于双框架,我的用法是:主跟一套,另一套只看。选 PyTorch 还是 Keras 看你后续要做什么。要做研究和自定义结构,PyTorch 的调试体验更顺;要快速搭原型给别人演示,Keras 的 API 更短。两套都读一遍的价值在于,你能看到同一个概念在不同抽象层级上的表达方式,比如“冻结骨干网络只训练分类头”,在 Keras 里是trainable = False,在 PyTorch 里是遍历参数改requires_grad,用途一样,写法完全不同。
提示:如果你只打算跑通不打算深入,别在双框架之间反复横跳。选定一套,把另一套的代码当成对照阅读材料,遇到不懂的 API 再回去查,效率高得多。
3. 核心模块拆解:四个实验看完整链路
课程的练习代码很多,但真正撑起整条学习曲线的是四类实验,规则推理、训练循环、卷积分类、文本向量化。把它们拆开看,你就知道这套课程的代码密度大概在什么水平,也能判断自己需要补哪块。
下面几段都是从课程练习里抽出来的最小骨架,我做过删减,去掉跟具体数据集绑定的部分,只保留结构。你可以直接放进自己的实验目录跑。
3.1 符号 AI:一个前向链推理引擎
课程在符号 AI 那一单元会用一个很小的规则推理例子,讲清“知识表示”和“推理”是两件事。这段代码不长,但它是整门课里唯一不涉及梯度的部分,很适合用来热身。
class Rule: """一条规则:前提条件全部满足时,推出结论""" def __init__(self, conds, conclusion, name=""): self.conds = set(conds) self.conclusion = conclusion self.name = name or conclusion def forward_chain(facts, rules, max_iter=50): """ facts: 初始事实集合,例如 {"有羽毛", "会飞", "下蛋"} rules: Rule 列表 返回:推导后的事实集合 + 触发过的规则名列表 """ facts = set(facts) fired = [] for _ in range(max_iter): # 防止规则互相推导导致死循环 hit = None for r in rules: # 条件全部已知,且结论还未出现过,才触发 if r.conclusion not in facts and r.conds <= facts: hit = r break if hit is None: # 没有新规则可触发,推理结束 break facts.add(hit.conclusion) fired.append(hit.name) return facts, fired rules = [ Rule({"有羽毛", "会飞"}, "是鸟类", "规则1"), Rule({"是鸟类", "不会飞"}, "可能是企鹅", "规则2"), ] facts, fired = forward_chain({"有羽毛", "会飞", "不会飞"}, rules) print(facts, fired)这段的逻辑是典型的前向链,从已知事实出发,反复扫描规则库,只要某条规则的前提被满足且结论尚未存在,就把结论加进事实集,直到没有新事实产生。max_iter是保护参数,防止规则集里存在循环依赖时无限推下去,一般设成规则条数的两三倍足够。conds <= facts用的是集合包含判断,要求前提全部命中,不是任意命中。
这段代码有个隐藏问题值得注意:{"有羽毛","会飞","不会飞"}这组事实本身是矛盾的,引擎不会报错,只会继续推出“是鸟类”和“可能是企鹅”。真实系统里,事实一致性校验要单独做一层,这是课程里没有展开但实际工程必须补的部分。
3.2 神经网络:把一个训练循环拆成五段看
神经网络那一单元的演示代码会从单个感知机讲到多层网络。真正值得反复看的是训练循环,几乎所有后续实验都是它的变体。下面这段是 PyTorch 版本:
import torch def train_one_epoch(model, loader, optimizer, criterion, device): model.train() # 切到训练模式,影响 Dropout/BatchNorm total_loss, correct, seen = 0.0, 0, 0 for x, y in loader: x, y = x.to(device), y.to(device) optimizer.zero_grad() # 必须清梯度,否则会跨 batch 累加 logits = model(x) loss = criterion(logits, y) loss.backward() # 反向传播,算出每个参数的梯度 optimizer.step() # 按优化器策略更新参数 total_loss += loss.item() * y.size(0) correct += (logits.argmax(1) == y).sum().item() seen += y.size(0) return total_loss / seen, correct / seen五段分别是:模式切换、清零梯度、前向、反向、更新。新手最容易漏的是optimizer.zero_grad(),漏了之后梯度会在 batch 之间累积,训练曲线看着在降,但学到的东西是错的,这种血泪经验基本人人都交过一次学费。
loss.item() * y.size(0)这里乘 batch 大小,是为了让最后一个不满批的 batch 也按样本数加权,算出来的平均损失才准确。如果直接对 batch 损失取平均,最后一个小 batch 会被过度放大。correct同理,按样本计数而不是按 batch 计数。
device这个参数是给 GPU 用的,课程里大部分小实验用 CPU 就够。判断标准很简单:单次 epoch 超过两三分钟才考虑上 GPU,否则数据搬运的开销比计算还大。
3.3 图像分类:卷积网络与迁移学习的两段代码
计算机视觉单元的代码量最大,但结构高度重复:加载数据、定义模型、训练、评估、可视化。真正有区分度的是迁移学习那一段,因为它引入了“冻结”这个概念。
import torchvision.models as models from torch import nn def build_model(num_classes=10, freeze=True): # weights=None 方便离线环境;联网时可换成预训练权重 model = models.resnet18(weights=None) if freeze: for p in model.parameters(): p.requires_grad = False # 冻结骨干,只训练分类头 model.fc = nn.Linear(model.fc.in_features, num_classes) return model参数说明:num_classes要跟你的数据集类别数对齐,课程示例里常见的是 10 类手写数字或服饰;freeze控制是否冻结骨干网络。冻结之后,只有最后那个全连接层参与梯度更新,训练速度快一个数量级,小数据集上也不容易过拟合。解冻的时机一般是:分类头收敛之后,用很小的学习率整体微调,比如 1e-4 或更低。
这里有个容易被忽略的细节:替换model.fc必须在冻结之后做,否则新建的分类层也会被冻上,训练一轮损失纹丝不动。我第一次就犯过这个低级错误,盯着日志看了半小时才反应过来。
课程里还会有目标检测和语义分割的演示,那部分代码依赖较大,跑之前先确认显存,这部分我在第 5 章会讲怎么估。
3.4 文本处理:从词袋到词向量的对比实验
自然语言处理单元会用同一个文本分类任务,分别跑词袋和词向量两种表示,让你直观看到差异。词袋那段代码很短:
from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.linear_model import LogisticRegression from sklearn.pipeline import make_pipeline # 中文语料务必先分词,用空格拼回去,否则 TF-IDF 会把整句当一个 token def build_baseline(): return make_pipeline( TfidfVectorizer(max_features=5000, ngram_range=(1, 2)), LogisticRegression(max_iter=1000) )max_features=5000控制词表规模,太大容易过拟合小语料;ngram_range=(1,2)表示同时取单词和二元词组,对短文本分类提升明显。这个基线的好处是训练只要几秒,你可以拿它当对照组,之后换词向量模型时,如果效果还不如它,说明问题出在数据处理而不是模型上。
中文版在这里有个绕不开的点:原课程的文本预处理假设是英文,按空格切词就行。中文语料必须先分词,接一层分词器,再把结果用空格连起来喂给向量化器。这一步不做,后面所有指标都没意义。
注意:课程里的词向量演示多为预训练模型加载,涉及下载。离线环境可以先跳过这一节,把词袋基线跑通,等网络方便时再补。
4. 把课程跑起来:环境、数据、执行顺序
环境这块,我的原则是:课程仓库一律用独立虚拟环境,不跟系统 Python 混。原因很实际,这种教学仓库的依赖通常很宽,跟别的项目共享环境,两个月后你回来想重跑,依赖已经被别的项目升级掉了。
4.1 环境搭建:三条命令加一个内核
# 1) 建独立环境,Python 3.10 兼容性最好 python -m venv .venv source .venv/bin/activate # Windows 用 .venv\Scripts\activate # 2) 装依赖,先装课程自带的清单 pip install -r requirements.txt pip install jupyter ipykernel # Notebook 本体和内核管理 # 3) 把虚拟环境注册成 Jupyter 内核,避免选错解释器 python -m ipykernel install --user --name ai-course --display-name "Python (ai-course)"这三步里第三步最容易被省掉,后果是打开 notebook 后默认选中的是某个全局内核,import一路报错。注册成命名内核之后,你在任何 notebook 里都能手动切到它,问题一眼就能定位。
关于 Python 版本,3.9 到 3.11 一般都没问题,但别用太新的版本,教学仓库的依赖往往没跟上。如果requirements.txt装到一半失败,先看是哪个包报错,再单独处理,不要一把梭升级所有包,那样会引入新的不兼容。
4.2 数据落位:先看清是随仓库还是运行时下载
课程里的数据集分两类。小数据集,比如手写数字、小型文本语料,通常随仓库带或者由框架内置下载函数拉取;大数据集,比如检测和分割用的图像集,一般是运行时下载,几个 GB 起步。
处理方式不一样。随仓库带的数据,确认路径跟 notebook 里的相对路径对上就行,常见写法是../data/xxx,你在子目录里打开 notebook 时路径基准会变,这是路径报错的主要原因。运行时下载的数据,第一次跑需要网络,下载完一般缓存在用户目录,比如~/.keras/datasets或~/.cache/torch,第二次就快了。想省事可以提前手动下好,放到缓存目录对应位置。
我一般会在课程根目录放一个check_env.py,跑一遍确认关键依赖和数据是否就位:
import importlib, os REQUIRED = ["numpy", "pandas", "matplotlib", "sklearn", "torch", "torchvision"] for name in REQUIRED: try: m = importlib.import_module(name) print(f"[OK] {name:12s} {getattr(m, '__version__', 'n/a')}") except Exception as e: print(f"[FAIL] {name:12s} {e}") # 顺手检查数据目录是否存在 for p in ["data", "lessons/04-computer-vision/data"]: print(("[OK] " if os.path.exists(p) else "[MISS] ") + p)这段脚本的价值不在技术含量,而在于把“环境问题”和“代码问题”分开。报错的时候先跑它,依赖齐了再去看 notebook,能省掉大量瞎猜。
4.3 执行顺序:从第一个单元格开始,别跳着跑
Notebook 的执行顺序是这类课程最大的隐形成本。讲义里写着“运行下面的单元格查看结果”,但那个单元格依赖上面某个定义变量的单元格,你从中间开始跑,就会遇到NameError。
我的做法是:每打开一个新 notebook,先Kernel → Restart & Run All,让它从头到尾跑一遍。跑通了,说明环境和数据都没问题,再回头按讲义节奏逐段看。跑不通,报错位置就是你要解决的第一个问题,比东点一下西点一下高效得多。
批量验证的话,命令行里可以这样跑,只执行不打开界面:
# 把整个单元目录跑一遍,输出写到临时文件,方便看是哪一步失败 jupyter nbconvert --to notebook --execute \ lessons/03-neural-networks/notebook.ipynb \ --output /tmp/out.ipynb \ --ExecutePreprocessor.timeout=600--ExecutePreprocessor.timeout默认是 30 秒,训练类 notebook 肯定不够,按你的数据规模调,600 秒是个比较稳的起点。--output指定输出路径,避免覆盖原始文件,这个细节很重要,课程原始 notebook 是你的参照物,跑坏了不好恢复。
5. 排查清单:五类让 Notebook 中途崩掉的坑
下面这几条都是我自己和身边人真实撞过的,按“现象、原因、解决”写,遇到问题可以直接对号入座。
5.1 内核直接挂掉,没有任何 Python 报错
现象:跑到训练那一段,单元格显示Kernel died或者内核重启,日志里没有 traceback。
原因:基本都是内存或显存被打满。课程里卷积和检测那几节的默认 batch size 是按有 GPU 的机器设的,你拿 8G 内存的笔记本跑,操作系统会直接杀掉进程,所以看不到 Python 层异常。
解决:先把 batch size 降到 8 或 4 再试,图像尺寸也从 224 往下降到 128。PyTorch 里可以在训练前打印torch.cuda.memory_allocated()观察增长;纯 CPU 环境用系统任务管理器看内存曲线。如果降了还是崩,检查是不是数据集整个被读进内存了,改成DataLoader流式加载。
5.2 ModuleNotFoundError,明明装过
现象:import torch报找不到模块,但终端里pip list明明有。
原因:Jupyter 用的内核和你装包的终端不是同一个 Python 环境。常见于没注册内核、或者用系统 pip 装了包但 notebook 跑在虚拟环境里。
解决:在 notebook 里执行import sys; print(sys.executable),看它指向哪个解释器。如果不是你的虚拟环境路径,说明内核选错了,按 4.1 的方式注册命名内核再切过去。另外,notebook 里临时装包可以在命令前加!,比如!pip install xxx,但这样装进的是当前内核的环境,容易让环境越来越乱,我一般只在临时调试时这么做。
5.3 数据集下载失败或路径找不到
现象:FileNotFoundError,或者下载函数卡住、返回 403。
原因有三类:路径相对基准变了、下载源在某网络环境下不稳定、缓存目录权限不够。
解决:先把 notebook 里拼路径的那行改成绝对路径试一次,能跑通就是路径基准问题。下载类问题,优先手动下载放到缓存目录,Keras 缓存在~/.keras/datasets,PyTorch 的 torchvision 一般在~/.cache/torch/hub/checkpoints。放进去之后重跑,框架会跳过下载直接用本地文件。
5.4 同样的代码,两次跑出来的准确率差很多
现象:每次Run All结果都不一样,浮动能有十几个百分点。
原因:随机种子没固定,包括 Python 的random、NumPy 的、框架自己的,还有数据加载时的 shuffle。另外 Notebook 的残留状态也会干扰,比如上一次训练定义的模型对象还在内存里。
解决:训练脚本开头统一设种子,并且每次实验前重启内核。
import random, numpy as np, torch def set_seed(seed=42): random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) torch.cuda.manual_seed_all(seed) torch.backends.cudnn.deterministic = True # 牺牲一点速度换可复现 torch.backends.cudnn.benchmark = False注意deterministic = True会让卷积变慢,只在需要严格复现时开,日常调参可以关掉。
5.5 中文文本实验效果异常差
现象:文本分类那一节,换中文语料后准确率接近随机猜。
原因:预处理流程还是英文那一套,按空格切词,整句变成一个 token,词表几乎没信息量;或者停用词表用的英文表,对中文没作用。
解决:在向量化之前插一层分词,把结果用空格连起来,再走原来的 TF-IDF 或词向量流程。分词粒度按任务定,短文本分类用词级一般够,长文本可以试字级。改完先看词表大小和前二十个高频词,如果高频词全是标点和“的”“了”,说明停用词没处理,补一张中文停用词表再跑。
提示:这五类问题里,前四类跟语言无关,第五类是中文版特有的。如果你在跑英文原版,可以跳过最后一条。
6. 二次开发:把课程代码改造成自己的实验模板
课程代码是为教学写的,变量名直白、结构扁平、参数写死在单元格里,直接拿来跑自己的数据会很别扭。我的做法是把它拆成三层:数据层、模型层、实验层,然后用一个配置文件把参数抽出去。
具体改造点有三个。第一,把每个 notebook 里的数据加载逻辑抽成datasets.py,统一出入口,换数据集只改这一处。第二,模型定义抽成models.py,用工厂函数按名字返回,方便横向对比。第三,训练循环抽成train.py,接收配置字典,输出指标和检查点。
配置化之后,一次实验就是一份 YAML:
# experiments/cnn_baseline.yaml 的读取与合并 import yaml BASE = {"seed": 42, "epochs": 10, "batch_size": 32, "lr": 1e-3, "img_size": 128} def load_config(path): with open(path, "r", encoding="utf-8") as f: cfg = yaml.safe_load(f) or {} merged = {**BASE, **cfg} # 文件里的键覆盖默认值 return merged # 用法:cfg = load_config("experiments/cnn_baseline.yaml")这样改的好处很直接:跑十组对照实验,你只需要改 YAML 里的一个数字,不用回到 notebook 里翻单元格找那行lr = 0.001。实验记录也好写,配置文件和指标一起存,三个月后回来看还能复现。
验证改造是否成功,我的标准是三条。换一次数据集能不能只改配置就跑通;同一个配置跑两遍指标是否一致;把某个模块替换成等价实现,接口是否不用动。三条都过,说明抽象层次合适了。
| 改造项 | 改造前 | 改造后 | 收益 |
|---|---|---|---|
| 数据加载 | 散落各单元格 | 统一 datasets.py | 换数据集改一处 |
| 超参数 | 硬编码 | YAML 配置合并 | 对照实验成本降低 |
| 训练循环 | 每节复制一份 | 单一 train.py | 修 bug 只修一次 |
| 结果记录 | 看单元格输出 | 指标写文件 | 可回溯可对比 |
最后说个教训。我早期做这类课程改造,喜欢一边读一边就地改 notebook,改到最后原始版本被我覆盖了,想对照原始实现都找不到,只能去重新拉一份。从那以后我每次动课程代码前,都先把原始 notebook 复制一份到baseline/目录,改成什么样都留着对照,跑不通就退回去看原版到底怎么写的。这个习惯看着笨,救过我很多次。希望帮到你。
本文还有配套的精品资源,点击获取