TensorFlow 是运算引擎,Keras 是搭在它上面的高层接口。 从 TensorFlow 2.0 起,Keras 被内置成 tf.keras,装一个包两样都有。 装之前先对版本:Python 版本、TensorFlow 版本、GPU 需要的 CUDA 与 cuDNN 版本, 这三层要能对得上,否则装完也是白装。 这台机器上没有 TensorFlow,也装不了。 所以这一节把 Keras 最核心的三个类手写一遍: 100 轮训练,损失 0.172062 降到 0.003043,准确率 0.9967,20 毫秒跑完。
第 2 章把 Python 装好了,这一章开始接触深度学习框架。 这一节是全章的地基:后面 NumPy、Matplotlib、Keras 体验都站在「什么装得上去」这件事上。 如果 41 课《图解深度学习》读过,那个课用的是纯 numpy 手写; 本书正好相反——书里用 Keras,实跑用 numpy,两本可以对着补。
一、两层关系
TensorFlow 是底层:管张量(多维数组)、管求导、管把运算扔到 CPU 或显卡上。
Keras 是上层:把「建层、编译、训练、评估」包成几个方法,让你少写代码。
TensorFlow 1.x 时代这两家是分开的,要另外 pip install keras。
2.0 之后官方把 Keras 收编,import tensorflow as tf 之后就能 tf.keras.Sequential。
现在还单独装 keras 包的人,多半是在跟老教程。新版 TensorFlow 不需要它,
多装一个反而容易出现版本错配。
二、版本要三层对上
深度学习框架的版本不是孤立的一件事,它卡在一条链上:驱动 → CUDA → cuDNN → 框架 → Python。 任何一环错位,表现都是「装成功了,但 import 报错」或者「能 import,但一跑就崩」。
| 层 | 错位时的典型症状 | 怎么查 |
|---|---|---|
| Python 版本 | 没有对应的 wheel,pip 直接找不到 | python --version |
| TensorFlow | import 报 DLL load failed | pip show tensorflow |
| CUDA/cuDNN | 能找到 GPU 但一算就崩 | tf.config.list_physical_devices |
| 显卡驱动 | 完全看不到 GPU | nvidia-smi |
先看驱动,再看 CUDA,最后才装框架。顺序反了,装完发现问题还得从头来。
三、装
CPU 版最简单:pip install tensorflow,一条命令,装完就能用,只是慢。
GPU 版要先装 NVIDIA 驱动和对应版本的 CUDA,再 pip install tensorflow。
不需要手动装 CUDA 的老版本了——新版 TensorFlow 会自己带一部分运行库,但驱动还是得自己装对。
国内网络装不动的话,用镜像源:pip install tensorflow -i 镜像地址。
镜像只是加速下载,包还是官方的包。
四、验证
装完要跑三行确认:
import tensorflow as tf
print(tf.__version__)
print(tf.config.list_physical_devices("GPU"))
第一行能过,说明装对了;第二行给出具体版本;第三行如果是空列表 [],说明只有 CPU,能跑但慢。
这三行是排查一切的起点。后面任何「跑不动」的问题,都先回来跑一遍这三行,
确认你现在用的到底是哪个版本、有没有显卡。
五、这台机器上怎么办
这台机器没有 TensorFlow,也没有 Keras,而且装不上——第 2 章那次包检查里,这两行结论都是「没装」。 所以本课定了一条规矩,从这一节开始一直用到最后: 教材里的 Keras 代码照原样抄进正文,标成「教材原码」;实跑一律换成 numpy 手写。 这不是偷懒。 手写一遍才知道 Keras 帮你省了什么、又藏了什么。第 4 章会手推梯度,第 5 章会手滑卷积窗, 都是同一个道理。
六、动手 Demo:装不上就自己造一个小的
先查这台机器上有什么,然后用 numpy 手写 Keras 最核心的两个类: Dense(一个全连结层)和 Sequential(把层串起来,提供 build/predict/fit)。 数据是两个高斯团,二分类。
import numpy as np
class Dense:
"""一个全连结层:z = xW + b,再过一个激励函数。"""
def __init__(self, units, act=None, seed=0):
self.units, self.act = units, act
self.rg = np.random.default_rng(seed)
def build(self, n_in):
self.W = self.rg.normal(0, 0.5, (n_in, self.units))
self.b = np.zeros(self.units)
def forward(self, x):
z = x @ self.W + self.b
if self.act == "sigmoid":
return 1.0 / (1.0 + np.exp(-z))
if self.act == "tanh":
return np.tanh(z)
return z
class Sequential:
def __init__(self, layers):
self.layers = layers
def build(self, n_in):
for ly in self.layers:
ly.build(n_in)
n_in = ly.units
def predict(self, x):
for ly in self.layers:
x = ly.forward(x)
return x
def fit(self, x, y, epochs=1, lr=0.5, verbose=0):
hist = []
for ep in range(epochs):
h = self.layers[0].forward(x)
p = self.layers[1].forward(h).ravel()
g = (p - y) / len(y)
hist.append(float(np.mean((p - y) * (p - y))))
dW2 = (h.T @ g).reshape(-1, 1)
gh = np.outer(g, self.layers[1].W.ravel()) * (1.0 - h * h)
self.layers[0].W -= lr * (x.T @ gh)
self.layers[1].W -= lr * dW2
self.layers[0].b -= lr * gh.sum(0)
self.layers[1].b -= lr * np.array([g.sum()])
return hist
实跑输出:
--------------------------------------------------------------------
TensorFlow 与 Keras 的安装:装不上就自己造一个小的
--------------------------------------------------------------------
包 这台机器上
--------------------------
tensorflow 没有
keras 没有
jupyter 没有
numpy 有
**TensorFlow 和 Keras 都没有。**这本书第 3 章之后的教材代码全是 Keras 写的,
所以后面每一节都按同一个规矩办:**教材原码照抄,实跑换成 numpy 手写。**
下面就把 Keras 最核心的三个类手写一遍,看清楚它到底在干什么。
用 Keras 的写法搭一个 2-8-1 的网络,跑 100 轮:
model = Sequential([Dense(8, act="tanh"), Dense(1, act="sigmoid")])
model.build(2)
hist = model.fit(X, y, epochs=100, lr=0.5, verbose=1)
epoch 20 loss 0.010928
epoch 40 loss 0.005550
epoch 60 loss 0.004114
epoch 80 loss 0.003442
epoch 100 loss 0.003043
首轮损失 0.172062 → 末轮 0.003043,准确率 0.9967,耗时 20 毫秒。
**这就是 Keras 干的事:把「建层、前向、反向、更新」四步包成三个方法。**
真正难的部分一行没省——只是你不用再手写那几行矩阵乘。
也正因为如此,第 4、5 章会把这几行重新拆开讲一遍。
tensorflow、keras、jupyter 三个都是「没有」,只有 numpy 有。所以后面凡是要跑 Keras 的地方,
都得先翻译成 numpy。
手写出来的 fit 跑 100 轮:
损失从 0.172062 降到 0.003043,准确率 0.9967,耗时 20 毫秒。这个速度和 Keras 差着数量级,
但算的是同一件事。
Keras 的 fit 内部做的正是这几行:前向算预测、算损失、反向算梯度、按学习率挪一步。
它快,是因为同样的运算跑在编译好的 C++ 和显卡上;它方便,是因为这四步你不用自己写。
注意 fit 里那个 verbose 参数——Keras 用它控制打不打进度条。
这里手写了一个简化版,每 20 轮打一行。这就是那个进度条的来源。
30 秒实验
- 把 epochs 从 100 改成 10 和 1000,看损失停在哪——1000 轮会不会过适?
- 把学习率从 0.5 改成 5.0,看损失是发散还是收敛得更快。
- 把隐层从 8 改成 2,准确率掉多少?这和 1.1 节那个「隐层数」的问题是一回事。
常见误区
- 以为装了 Keras 才能用 Keras。TensorFlow 2.x 起 Keras 就在里面,
tf.keras直接用。 单独装 keras 包是给老版本的用法。 - 以为 import 成功就是装好了。DLL 缺失、CUDA 版本不对,都可能在第一次做矩阵乘的时候才崩。 要跑一次真正的运算才算验证过。
- 以为 GPU 版一定比 CPU 版快。小模型、小批量时,数据在内存和显存之间搬的时间可能比计算还长, 反而不如 CPU。
自测三问(点开对答案)
1. TensorFlow 和 Keras 是什么关系? —— TensorFlow 是底层的张量运算与自动求导引擎,Keras 是建在它上面的高层接口。 2.0 之后 Keras 内置为 tf.keras,装 TensorFlow 就有了。 2. 为什么版本要「三层对上」? —— 因为 Python 决定能装哪个 wheel,框架版本决定要哪个 CUDA,CUDA 又要求驱动足够新。 任何一层错位,表现都是「装了但跑不了」。 3. tf.config.list_physical_devices 返回空列表说明什么? —— 说明 TensorFlow 没看到可用的 GPU,只能用 CPU 跑。能跑,但训练速度会差一个量级以上。框架装好了,接下来是写代码的地方。 下一节讲 Jupyter Notebook——书里所有例子都是在那儿写的,而它有一个很多人踩过的坑:执行顺序。
- ☐ (本节完,下一节 3.2 使用 Jupyter Notebook)