跳到主要内容

同一段逻辑怎么复用,顺手写出第一个神经元

这一章讲三件事: 同一段逻辑怎么才能只写一遍; 「类」到底是拿来干什么的;以及 —— 这才是真正的落点 —— 一个「人工神经元」被写出来之后长什么样。 它在全书链条里的位置是第 3 级台阶: 数据能进程序了,接下来的问题是「谁来算」。 遇到的生词都在当场解释。

1. 顶层全景

同一段逻辑要用很多遍

│ ① 最小的复用单位:函数——给一段代码起个名字,以后叫名字就行

函数

│ ② 但有的东西「数据」和「操作」是长在一起的
│ (一辆车有速度、方向,也有加速、转向的动作)

类:把数据和操作捆成一个整体

│ ③ 拿这两样东西各写一遍同一个东西——

一个人工神经元

│ 输入 ×权重 → 全部加起来 → +偏置 → 过一道判断

输出:+1 或 −1

图说:这一章的落点在最下面那一格。
前面两格是工具,最后一格才是这本书真正要走的那条路的第一步。

本章主走查: 平面上四个点 —— 标 +1 的 (5, 4) 和 (4, 5),标 −1 的 (1, 2) 和 (3, 2)。 这四个点是书给的1。我们会拿一个神经元把它们分成两类, 先用函数写一遍,再用类写一遍,两遍的每一个中间结果都写出来

2. 为什么不能复制粘贴

先看现象

书开头给的例子很实在:训练模型的时候,每一轮结束都要读一批新数据进来, 所以「读数据」这段代码要被反复用到。如果没有复用手段, 就得写很多行代码来反复实现同一件事2

复制粘贴的真正代价不是打字多,是改的时候。 同一段逻辑复制了八处, 哪天发现它有个 bug —— 你要改八处,而且一定会漏掉一处。

做法:拆成模块,让模块之间尽量互不打扰

书把这件事叫模块化设计:把一段长程序分割成独立的模块,每块完成特定功能。 它给了一个判断好坏的标准3:

意思好不好
紧耦合模块内部各部分关系紧密,拆不开模块内部应该这样
松耦合模块之间关系尽可能简单,各自能独立存在模块之间应该这样

一句话:里面抱成团,外面少牵扯。

书还给了三条原则4:接口要定清楚(明确输入输出); 一个模块只负责一件事;模块之间依赖抽象、不依赖具体实现。

函数是最小的那个模块。

3. 函数:给一段代码起个名字

定义与调用

def clamp(value, low, high): # def 起头,后面是名字和参数列表
"""把 value 限制在 low 和 high 之间"""
if value < low:
return low
if value > high:
return high
return value

print(clamp(1.4, -1, 1)) # 调用,输出 1

书给了几条规则5:def 起头;参数放在圆括号里;函数体要缩进; return 结束函数并交回一个值,不带值的 return 相当于返回「什么都没有」

形参和实参:两个容易混的词

这两个词书特意区分了6:

在哪儿是什么
形参(形式参数)定义函数时括号里的那些名字占位符,等着接收值
实参(实际参数)调用函数时括号里给的那些值真正传进去的东西

上面那段里,valuelowhigh 是形参;1.4-11 是实参。

四种传参方式

方式长什么样什么时候用
位置参数clamp(1.4, -1, 1)参数少、顺序一目了然
关键字参数clamp(value=1.4, high=1, low=-1)参数多的时候 —— 写了名字就不用管顺序7
默认参数def clamp(value, low=-1, high=1)大多数时候都是同一个值。注意:带默认值的必须排在后面8
可变参数def f(*args)参数个数事先不知道。带一个星号的按元组传进来9

一个安静的坑:函数里改了外面那个列表

这个坑和第 03 章那个 lt = ls 是同一件事,换了一副面孔。

ls = ["S", "T"]

def func():
ls.append("D") # 没有在函数里重新造一个 ls,动的就是外面那个

func()
print(ls) # ['S', 'T', 'D'] —— 外面那个被改了

书讲得很准:当一个组合类型的变量在函数内部没有被真实创建时, 函数里用的、改的就是外面那个10反过来,只要函数里真的造了一个同名的新列表, 外面那个就一动不动。

情况一:函数里没造新的 情况二:函数里造了新的
外面 ls ──┐ 外面 ls ──▶ ["S","T"] ← 没被碰
├──▶ ["S","T","D"]
函数里 ls ┘ 函数里 ls ──▶ ["S","T"] ← 另一份,函数退出就没了

图说:判据是「函数里有没有一句给它重新赋值」。
有,就是两份;没有,就是同一份。

默认情况下函数里的变量是「局部」的 —— 函数一结束就没了,不影响外面同名的那个; 要在函数里明确地改外面那个,得用 global 声明11

4. 类:把数据和对它的操作捆在一起

第 03 章已经讲过怎么「用」别人给的对象。这一节讲怎么「造」一个。

先看现象:为什么函数不够用

假设你要管三辆赛车,每辆有编号、速度、方向。用函数写:

def set_info(number, velocity, direction): ...
def show_info(number, velocity, direction): ...

每次调用都得把三个数一起端过去。 车一多、属性一多,参数列表就爆炸了 —— 而这三个数明明本来就是一辆车身上的东西,应该跟着车走。

做法:让数据跟着东西走

书给的定义:面向对象编程把对象作为程序的基本单元, 一个对象包含了数据和操作数据的函数;具有相同属性和操作方法的对象被抽象为, 而对象是类的实例12

书给的比方很好用:类相当于一个模板,对象就是用模板生产出来的零件。 再具体一点:类像一份赛车的蓝图,蓝图能展示赛车的属性和方法,但它本身不是一辆赛车13

class RacingCar:
def __init__(self, number): # 造一辆车的时候自动跑这一句
self.number = number # 属性:跟着这辆车走
self.velocity = 0
self.direction = 0

def set_info(self, velocity, direction): # 方法:第一个参数必须是 self
self.velocity = velocity
self.direction = direction

def show_info(self):
print("车 {} 速度 {} 方向 {}".format(self.number, self.velocity, self.direction))

car1 = RacingCar("A01") # 实例化:照蓝图造一辆出来
car1.set_info(60, -0.4) # 只传两个数,车的编号跟着 car1 走
car1.show_info() # 车 A01 速度 60 方向 -0.4

三个必须解释的地方

写法意思
class定义一个类。类名习惯用首字母大写14
__init__构造方法。每次照这个类造出一个实例时,它会先被执行一遍15
self类里定义方法时第一个参数必须是它,而且调用时不用传 —— 它代表当前这一个实例16

self 是最容易卡住的一个。 一句话: self.velocity 的意思是「我这辆车的速度」,而不是「所有车的速度」。

RacingCar 这个类(蓝图)

├── car1 = RacingCar("A01") → 一辆独立的车,有自己的 velocity
├── car2 = RacingCar("A02") → 另一辆,velocity 和 car1 无关
└── car3 = RacingCar("A03")

car1.set_info(60, -0.4) 里那个 self,指的就是 car1。
图说:方法只有一份(写在类里),数据每个实例一份。

一条要留心的:「私有」只是君子协定

书讲得很直白:Python 类并没有真正意义上的私有属性。 用两个下划线开头定义的属性只是一种程序员约定俗成的规定 —— 加了表示「别从外面动它」,但如果在外部调用,还是可以调用的17

这一条要记住,因为它和很多别的语言不一样。 Python 这里靠的是自觉,不是强制。

继承:书讲了,但这本书后面几乎没用上

一个类可以继承另一个类,拿到它全部的属性和方法; 父类的方法不合用还可以在子类里重写。Python 甚至支持一个类同时继承多个父类18

照实说:这本书后面十二章里,继承一次都没有真正用上。 我们不展开,知道有这回事、看到 class A(B): 这种写法认得出就够了。

5. 现在写第一个人工神经元

这是本章的落点,也是全书那条推理链的第 4 步:数据齐了,谁来算?

先看现象:它没有你想的那么神秘

「神经网络」这个词唬人,但它最小的那个零件朴素到有点让人失望。

它做两件事,就两件:

① 每个输入各乘一个数,全部加起来,再加一个数
② 把结果丢给一道判断,由它决定输出什么

完了。

第一步:加权求和

书给的式子是:z = w₁x₁ + w₂x₂ + … + b19。三个词就地解释:

符号名字是什么
x₁, x₂, …输入这次要判断的那个东西的几个数值特征
w₁, w₂, …权重每个输入有多要紧。大就说明这个输入说了算
b偏置一个和输入无关的常数,整体把结果往上或往下推一推

「权重」这个词值得停一下: 它就是字面意思 —— 加权平均里的那个「权」。 你综合几个指标打分时给每项定的分量,是同一回事。

「偏置」的直觉: 想象一条及格线。加权求和给出一个分数, 偏置决定这条线画在哪儿 —— 把 b 调大,更容易「过」;调小,更难「过」。

第二步:过一道判断

把 z 交给一个函数,由它决定最终输出什么。这个函数叫激活函数 —— 就是第 02 章 §4 那个名字。

这里书用的是最简单的一种:大于等于某个门槛就输出 +1,否则输出 −120。 (数学上叫符号函数,写作 sgn。)

x₁ ──w₁──┐
├──▶ 加起来 + b ──▶ z ──▶ 判断 ──▶ +1 或 −1
x₂ ──w₂──┘

图说:整个「人工神经元」就这么大。
x 是这次要看的东西,w 和 b 是它「学到的经验」,输出是它的判断。

它从哪儿来:1957 年,以及一个生物学的比方

书给了来历:1957 年 Frank Rosenblatt 提出了一种简单的人工神经网络,称为感知器; 早期的它只有一个输入层和一个输出层,所以叫单层感知器; 它是一个二分类模型 —— 只输出两种结果(是 / 不是,+1 / −1); 而且是线性的 —— 分界面是一条直线,不是曲线21

灵感来自生物神经元,而且是逐个功能对上的22:

生物神经元人工神经元
树突接收信号输入层接收 x
细胞体加工处理加权求和
轴突控制输出激活函数
突触把结果传出去输出层

这是个比方,用完就拆: 借的只是「接收 → 汇总 → 决定 → 输出」这个结构, 不是说这东西像脑子。本章后面一律叫它「神经元」或「感知器」,不再提生物。

6. 主走查:用函数写一遍

四个点是书给的,权重和偏置是我们定的。

输入

标 +1 的点:(5, 4) 和 (4, 5)
标 −1 的点:(1, 2) 和 (3, 2)

画在坐标纸上:右上角两个是 +1,左下角两个是 −1。
任务:找一条直线把它们分开。

我们取 w = (1, 1)、b = −6,门槛取 0。 这组数是我们为演示定的,不是书给的 —— 它对应的分界线是 x₁ + x₂ = 6。

示范代码(我们写的,不是书里的)

书这里的代码是图片,清洗文本里没有;书只说它定义了两个函数, 一个算加权和(书写作「静活值函数」)、一个是激活函数23。我们照这个结构写:

def net_input(x, w, b): # 加权求和
total = b
for i in range(len(x)):
total = total + x[i] * w[i]
return total

def active(z): # 激活:大于等于 0 输出 +1,否则 −1
return 1 if z >= 0 else -1

W = [1, 1]
B = -6
points = [([5, 4], 1), ([4, 5], 1), ([1, 2], -1), ([3, 2], -1)]

for x, label in points:
z = net_input(x, W, B)
y = active(z)
print(x, "z =", z, "输出", y, "标签", label, "对" if y == label else "错")

走查:四个点逐个走,每一步写出具体的数

点 (5,4) 标 +1
加权求和: z = 1×5 + 1×4 + (−6) = 5 + 4 − 6 = 3
激活: 3 ≥ 0 ⇒ 输出 +1 ✅ 对

点 (4,5) 标 +1
加权求和: z = 1×4 + 1×5 − 6 = 3
激活: 3 ≥ 0 ⇒ 输出 +1 ✅ 对

点 (1,2) 标 −1
加权求和: z = 1×1 + 1×2 − 6 = −3
激活: −3 < 0 ⇒ 输出 −1 ✅ 对

点 (3,2) 标 −1
加权求和: z = 1×3 + 1×2 − 6 = −1
激活: −1 < 0 ⇒ 输出 −1 ✅ 对

四个点全对。
图说:这条神经元其实就是在问「x₁ + x₂ 有没有超过 6」。
权重决定两个坐标各占多大分量,偏置决定那条线画在哪儿。

一句必须说的话:这组权重是我们硬塞进去的

w = (1, 1)、b = −6 不是算出来的,是我们看着这四个点凑的。

真正的问题是:换一批点、换一个任务,这些数从哪儿来?

答案是:它们本该是「学」出来的,不是人定的。 书在第 8 章给了这个更新式:权重 += 学习率(学习率 = 每次挪多大一步,书说它取 0 到 1 之间) × (真实标签 − 当前输出) × 这个输入24拿这四个点从零起手、把权重真的训一遍 —— 第 06 章讲。

7. 再用类写一遍:一模一样的账

书自己把同一个感知器写了两遍,而且明说两者「实现的功能是完全一样的, 只是编程的思路转变了」25

class Neuron:
def __init__(self, w, b):
self.w = w # 属性:这个神经元自己的权重
self.b = b # 属性:自己的偏置

def net_input(self, x): # 方法
total = self.b
for i in range(len(x)):
total = total + x[i] * self.w[i]
return total

def active(self, x):
return 1 if self.net_input(x) >= 0 else -1

n = Neuron([1, 1], -6)
print(n.net_input([5, 4]), n.active([5, 4])) # 3 1
print(n.net_input([1, 2]), n.active([1, 2])) # -3 -1

同一笔账,同样的数: (5,4) → z = 3 → +1;(1,2) → z = −3 → −1。

那么差别在哪

差别只有一个:数据跟着谁走。

函数版类版
权重和偏置放在哪在外面,每次调用都要传进去在这个神经元身上,造它的时候就定了
想同时有两个不同的神经元得自己管两套 W、B 别弄混n1 = Neuron(...)n2 = Neuron(...),各自独立
代码行数少一点多一点

当只有一个神经元时,函数版更省事;当有几百万个时,类版是唯一可行的。 后面所有框架里的模型,都是类。

8. 训练数据是怎么来的:一条流水线

这一节是本章最后一格,它把「神经元」和「这辆车」接上。

现象先行:标签从哪儿来

第 01 章说过,要教会模型「看到这张图该打多少角度」,就得有成千上万对 「图 + 转角」。这些转角是谁标的?

答案很妙:没有人标。是开出来的。

那条流水线

书在第 4 章的最后一个实例里把它交代了26:

① 人拿遥控器,开着车沿赛道走

② 车头前置摄像头一路拍,每个位置拍一张

③ 同时记下此刻手上打的转向角度
│ 正值 = 右转,负值 = 左转,0 = 直行

④ 把角度归一化到 [−1, 1]

⑤ 存成「图片名 → 转角」的对应关系

图说:人开一圈,数据就有一圈。标注这件事被「开车」这个动作顺手做掉了。
第 13 章训练用的数据,就是这么来的。

「归一化」这个词,在这里就地讲透

第 ④ 步那个词后面会反复出现,现在把最朴素的一层讲清楚:

归一化 = 把量程不同的数,按同一把尺子压到同一个区间里。

这里具体是什么意思:遥控器的摇杆能转多少度,每个手柄都不一样 —— 有的能转 30 度,有的能转 45 度。如果直接把度数存进去, 换一个手柄,同样的「打满」就变成了另一个数,模型全乱套。

手柄 A:摇杆最多转 ±30° 打到 −12° ──┐
手柄 B:摇杆最多转 ±45° 打到 −18° ──┤ 压到同一把尺子上

都是 −0.4

图说:归一化之后,数字的含义和硬件脱钩了。
−0.4 永远表示「往左打了四成」,不管这个手柄本身能转多少度。
这两个角度值是为演示编的。

归一化对训练还有另外两个好处 —— 那要等到模型真的开始训练时才说得清, 第 09 章讲

采得多了怎么办:同一张图录了三次

第 03 章讲过:书把这套数据存成字典,同一张图多次录入就把转角都存进一个列表, 取的时候求平均27理由很实在:人手遥控本来就抖,单次读数不可靠。

9. 作者的判断与证据

说法是哪一类
紧耦合 / 松耦合、模块化三原则教科书式的共识,书没给出处。当成经验法则,不是定理
组合类型在函数内未真实创建时改的是外面那个有证据: 语言事实,书给了两个可复现的对照实例
Python 的私有属性只是约定有证据: 语言事实
感知器由 Rosenblatt 于 1957 年提出书正文写 1957,而书末参考文献 [14] 是 1958 年那篇。 两个年份各有出处(1957 年的技术报告、1958 年的期刊论文),不算错,但书没说明这个差别
「一个单层感知器可以简单理解为一个线性回归模型」作者的类比,而且很重要 —— 第 06 章正是靠这句话把感知器和线性回归接上的
生物神经元与人工神经元的功能对照作者的类比。 借的是结构,不是说它像脑子
「实例 4.22 和实例 4.16 实现的功能完全一样」有证据: 书自己点明的,我们也重算过
采集速度、转向要平滑这些经验本章不涉及,那些在第 13 章

一处排版错字,顺手指出

书在第 4 章把加权求和那个函数写成「活值函数」, 而第 8 章讲反向传播时用的是「活值」28同一个东西,两个字。第 8 章那个是对的 —— 它指的是「还没过激活函数的那个净输入」。

我们的一条判断

判断(我们的,不是书里的): 这一章真正的价值,是它把「神经元」这个词祛魅了。 读完你会发现那个被叫做「人工神经元」的东西,加起来只有一句加权和加一道判断 —— 十行代码写得完,而且你能自己算出每一步。 后面十一章里所有看起来很唬人的东西(几十万个参数、上百层), 都是这一句在数量上重复,不是在原理上变复杂。 如果错,会错在: 如果某类模型的基本单元并不是「加权和 + 一道判断」这个形状 (比如换成别的运算结构),那这条「只是数量上重复」的说法就要收窄成 「对这本书讲的这一类网络成立」。判据是:翻开任何一个现代模型, 它最里面那一层还是不是在做乘加。

10. 边界与局限

  • 本章对应原书第 4 章,外加从第 8 章 8.1.2 节前移过来的两小块: 生物神经元的功能对照,以及「训练就是学权重和偏置」那一句。
  • 书里的代码全是图片。 本章所有代码都是我们照书的文字描述自己写的
  • 递归和汉诺塔整体不采用。 原书讲了(还给了 64 个盘子的经典问题), 但全书后面一次都没用到。
  • 匿名函数(lambda)只提一句。 同上,后面用不到。
  • 继承讲到「认得出写法」为止。 后面十二章没有真正用它。
  • PID 控制器只在本章的习题里出现,正文一个字没讲。 书给了位置式和增量式两个公式,要求学生自己封装成类 —— 但正文从未解释它是什么。 这是一个真实缺口:第 14 章要把「看清车道线」变成「车真的转起来」时, 缺的正是这一环。我们在第 14 章照实写明。
  • 感知器只讲了「怎么算」,没讲「怎么学」。 这是原书的编排问题: 第 4 章给结构、第 8 章才给更新式,中间隔了四章。我们把「怎么学」放在第 06 章。

11. 可带走的

全章主走查一行写完: 四个点 (5,4)+1、(4,5)+1、(1,2)−1、(3,2)−1; 取 w = (1,1)、b = −6 → 逐点算加权和:3、3、−3、−1 → 过判断(≥0 给 +1,否则 −1)→ +1、+1、−1、−1,四个全对;同一笔账用函数写一遍、用类写一遍,结果一模一样。 四个点是书给的;w、b 和门槛是我们为演示定的。

  1. 复制粘贴的代价不在打字,在改 —— 复用靠拆模块,模块内部抱成团、模块之间少牵扯;
  2. 形参是定义时的占位符,实参是调用时真正传进去的值;
  3. 函数里没有重新创建的组合类型变量,改的就是外面那个 —— 这和第 03 章 lt = ls 是同一个坑;
  4. 类是模板,实例是照模板造出来的那一个;self 的意思永远是「当前这一个」;
  5. Python 的「私有」只是君子协定,外面照样调得到;
  6. 一个人工神经元只做两件事: 输入各乘一个权重、加起来再加偏置;把结果交给激活函数;
  7. 权重 = 每个输入有多要紧;偏置 = 那条判定线画在哪儿;
  8. 这就是 1957 年的单层感知器 —— 一个二分类的线性模型,它只画得出一条直线;
  9. 同一个感知器写成函数和写成类,功能完全一样,差别只在「数据跟着谁走」 —— 一个神经元时函数版更省事,几百万个时只能用类;
  10. 训练数据是「开出来的」不是标出来的: 人遥控车跑一圈,摄像头拍图、 程序同时记下转角、归一化到 [−1,1] —— 归一化就是把不同量程的数压到同一把尺子上;
  11. 那组权重是硬塞进去的,它本该是学出来的 —— 怎么学,第 06 章讲。

12. 原文地图

主题原书章原文位置
代码复用的动机(训练时反复读数据)第4章 函数和类text/05-ch04.txt:7(搜「读取数据的方法被反复使用」)
模块化设计;紧耦合与松耦合;三条原则第4章 函数和类text/05-ch04.txt:15(搜「模块内部紧耦合」) · text/05-ch04.txt:21(搜「定义清晰的接口」)
函数定义规则;return第4章 函数和类text/05-ch04.txt:43(搜「def关键词开头」)
形参与实参第4章 函数和类text/05-ch04.txt:55(搜「形参用于接收函数调用时传入的值」) · text/05-ch04.txt:69(搜「实际参数是函数调用时使用的参数」)
位置 / 关键字 / 默认 / 可变参数第4章 函数和类text/05-ch04.txt:73(搜「位置参数是最常见」) · text/05-ch04.txt:79(搜「关键字参数」) · text/05-ch04.txt:85(搜「默认参数要放在」) · text/05-ch04.txt:91(搜「可变参数」)
局部与全局变量;组合类型在函数内的行为第4章 函数和类text/05-ch04.txt:115(搜「局部变量是指在函数内部使用的变量」) · text/05-ch04.txt:125(搜「未在函数」)
面向对象的基本概念;类是模板第4章 函数和类text/05-ch04.txt:175(搜「对象(Object)是类的实例」) · text/05-ch04.txt:209(搜「就像是一份赛车的蓝图」)
公有 / 私有属性;私有只是约定第4章 函数和类text/05-ch04.txt:213(搜「私有属性由两个下画线开头」) · text/05-ch04.txt:215(搜「并没有真正意义上的私有属性」)
self 必须是第一个参数;__init__ 构造方法第4章 函数和类text/05-ch04.txt:221(搜「必须包含参数self」) · text/05-ch04.txt:225(搜「特殊方法(构造函数)」)
继承与多继承第4章 函数和类text/05-ch04.txt:243(搜「派生类的定义」) · text/05-ch04.txt:251(搜「多重继承」)
单层感知器:1957、二分类线性模型、结构第4章 函数和类text/05-ch04.txt:143(搜「Frank Rosenblatt」)
加权求和式子与偏置项第4章 函数和类text/05-ch04.txt:151(搜「z=wx+wx」) · text/05-ch04.txt:155(搜「偏置项(bias)」)
激活函数取符号函数;输出 1 或 −1第4章 函数和类text/05-ch04.txt:161(搜「与某一阈值进行比较」)
函数版感知器定义了哪两个函数第4章 函数和类text/05-ch04.txt:163(搜「静活值函数」)
类版感知器;两个实例功能完全一样第4章 函数和类text/05-ch04.txt:271(搜「只是编程的思路转变了」)
数据采集流水线(遥控 → 拍照 → 记角度 → 归一化)第4章 函数和类text/05-ch04.txt:263(搜「遥控赛车沿着赛道行进」)
PID 只出现在习题里第4章 函数和类text/05-ch04.txt:377(搜「位置式PID」) · text/05-ch04.txt:387(搜「增量式PID的离散公式」)
生物神经元与人工神经元的功能对照第8章 深度学习基础及车辆识别项目实践text/09-ch08.txt:31(搜「模拟生物神经元的树突」)
「单层感知器可以理解为线性回归模型」;训练 = 学权重和偏置;学习率 η第8章 深度学习基础及车辆识别项目实践text/09-ch08.txt:35(搜「线性回归模型」) · text/09-ch08.txt:37(搜「学习获得它的权重和偏置」) · text/09-ch08.txt:39(搜「取值范围为(0,1)」)
实例 8.1 那四个点第8章 深度学习基础及车辆识别项目实践text/09-ch08.txt:41(搜「标签为1的(5,4)」)
「净活值」的写法第8章 深度学习基础及车辆识别项目实践text/09-ch08.txt:193(搜「净活值为neth1」)

Footnotes

  1. 出处:「第8章 深度学习基础及车辆识别项目实践」第 41 段(text/09-ch08.txt:41,搜「标签为1的(5,4)」)。原文:平面坐标系上有 4 个点,标签为 1 的是 (5,4) 和 (4,5),标签为 −1 的是 (1,2) 和 (3,2),要求构建一个单层感知器把它们分成两类。书没有给出对应的权重和偏置(那部分是代码,而代码是图片),所以本章走查里的 w=(1,1)、b=−6 是我们为演示定的。

  2. 出处:「第4章 函数和类」第 7 段(text/05-ch04.txt:7,搜「读取数据的方法被反复使用」)。原文举的正是深度学习训练的例子:一个轮次训练结束会读取新的数据进行训练。

  3. 出处:「第4章 函数和类」第 15 段(text/05-ch04.txt:15,搜「模块内部紧耦合」)。原文:这种分而治之、分层抽象、体系化的设计思想可以使模块内部紧耦合、模块之间松耦合。

  4. 出处:「第4章 函数和类」第 21—25 段(text/05-ch04.txt:21,搜「定义清晰的接口」)。三条依次是:定义清晰的接口、单一职责原则、依赖倒置原则。

  5. 出处:「第4章 函数和类」第 41—51 段(text/05-ch04.txt:43,搜「def关键词开头」)。

  6. 出处:「第4章 函数和类」第 55 段(text/05-ch04.txt:55,搜「形参用于接收函数调用时传入的值」)与第 69 段(text/05-ch04.txt:69,搜「实际参数是函数调用时使用的参数」)。

  7. 出处:「第4章 函数和类」第 79 段(text/05-ch04.txt:79,搜「关键字参数」)。原文特别点明:用了关键字之后,参数位置的不同不影响输出结果。

  8. 出处:「第4章 函数和类」第 85 段(text/05-ch04.txt:85,搜「默认参数要放在」)。

  9. 出处:「第4章 函数和类」第 91 段(text/05-ch04.txt:91,搜「可变参数」)。原文说明加一个星号时按元组传递,加两个星号时按字典传递。

  10. 出处:「第4章 函数和类」第 125 段(text/05-ch04.txt:125,搜「未在函数」)。原文给了两个对照实例:函数内没有真实创建同名列表时,运行结果是 ['S', 'T', 'D'];函数内创建了局部列表时,结果是 ['S', 'T']

  11. 出处:「第4章 函数和类」第 115 段(text/05-ch04.txt:115,搜「局部变量是指在函数内部使用的变量」)与第 123 段(text/05-ch04.txt:123,搜「global保留字」)。

  12. 出处:「第4章 函数和类」第 175 段(text/05-ch04.txt:175,搜「对象(Object)是类的实例」)。原文:「面向对象编程把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。」

  13. 出处:「第4章 函数和类」第 209 段(text/05-ch04.txt:209,搜「就像是一份赛车的蓝图」)。

  14. 出处:「第4章 函数和类」第 203 段(text/05-ch04.txt:203,搜「class关键字来定义」)。

  15. 出处:「第4章 函数和类」第 225 段(text/05-ch04.txt:225,搜「特殊方法(构造函数)」)。原文:每当类被实例化时,就会先执行该构造方法。

  16. 出处:「第4章 函数和类」第 221 段(text/05-ch04.txt:221,搜「必须包含参数self」)。原文:「self 代表的是类当前的实例化对象,在调用时,不需要给这个参数传值。」

  17. 出处:「第4章 函数和类」第 215 段(text/05-ch04.txt:215,搜「并没有真正意义上的私有属性」)。原文的建议是「遵守约定俗成的规定以避免不必要的麻烦」。

  18. 出处:「第4章 函数和类」第 243 段(text/05-ch04.txt:243,搜「派生类的定义」)与第 251 段(text/05-ch04.txt:251,搜「多重继承」)。

  19. 出处:「第4章 函数和类」第 151 段(text/05-ch04.txt:151,搜「z=wx+wx」)与第 155 段(text/05-ch04.txt:155,搜「偏置项(bias)」)。清洗文本里下标掉成了独立的一行(text/05-ch04.txt:153,搜「1122」),那是排版残留,不是内容缺失。

  20. 出处:「第4章 函数和类」第 161 段(text/05-ch04.txt:161,搜「与某一阈值进行比较」)。原文:如果大于等于该阈值则输出 1,否则输出 −1。

  21. 出处:「第4章 函数和类」第 143 段(text/05-ch04.txt:143,搜「Frank Rosenblatt」)。要留心一处: 正文写的是 1957 年,而书末参考文献 [14] 给的是 ROSENBLATT F. 1958 年发表在 Psychological Review 上的那篇(text/13-fm.txt:31,搜「Psychological review」)。两个年份分别对应 1957 年的技术报告和 1958 年的期刊论文,不算错,但书没有说明这个差别。

  22. 出处:「第8章 深度学习基础及车辆识别项目实践」第 31 段(text/09-ch08.txt:31,搜「模拟生物神经元的树突」)。原文逐项给出了对照:输入层对应树突接收输入信号,加权和对应细胞体加工处理,激活函数对应轴突控制输出,输出层对应突触。

  23. 出处:「第4章 函数和类」第 163 段(text/05-ch04.txt:163,搜「静活值函数」)。原文说明实例里定义了两个函数,一个求加权和、一个是激活函数。代码本体是图片,所以本节的示范代码是我们写的。

  24. 出处:「第8章 深度学习基础及车辆识别项目实践」第 37 段(text/09-ch08.txt:37,搜「学习获得它的权重和偏置」)与第 39 段(text/09-ch08.txt:39,搜「取值范围为(0,1)」)。原文:「对于单层感知器来讲,训练的过程就是学习获得它的权重和偏置的过程」;更新公式本体是图片,但文字里给出了学习率 η 及其取值范围。

  25. 出处:「第4章 函数和类」第 271 段(text/05-ch04.txt:271,搜「只是编程的思路转变了」)。原文:「实例 4.22 和实例 4.16 实现的功能是完全一样的,只是编程的思路转变了」,并说明 x 和 w 是类的属性、两个函数是类的方法。

  26. 出处:「第4章 函数和类」第 263 段(text/05-ch04.txt:263,搜「遥控赛车沿着赛道行进」)。原文完整给出了这条流水线:人遥控赛车沿赛道行进,前置摄像头拍下每个位置的照片,同时记录手动遥控的转向角度和速度,角度正值为右转向、负值为左转向、0 为直行,转角值经归一化处理后落在 [−1,1] 之间。两个手柄的角度例子是我们为演示编的。

  27. 出处:「第5章 组合数据类型」第 231 段(text/06-ch05.txt:231,搜「求多次输入转向角的平均值」)。

  28. 出处:「第4章 函数和类」第 163 段(text/05-ch04.txt:163,搜「静活值函数」)对比「第8章 深度学习基础及车辆识别项目实践」第 193 段(text/09-ch08.txt:193,搜「净活值为neth1」)。同一个概念在两章里写成了两个不同的字,第 8 章那个「净」是对的。