感知机的工作原理
假设你有一个任务,就是根据天气预报来决定今天是否要带伞出门。你的决策依据有两个特征:
- 是否下雨(0 表示不下雨,1 表示下雨)。
- 风力大小(0 表示无风,1 表示有风)。
现在,我们用感知机来帮助我们做决定:
- 我们需要给每个特征分配一个权重(weight)。权重表示该特征对最终决定的影响程度。例如,如果“是否下雨”对我们来说更重要,那么它的权重可能会更高。
- 我们还需要一个阈值(bias),它可以理解为我们对是否带伞的“倾向性”。即使没有任何特征表明需要带伞,如果阈值足够高,我们仍然会决定带伞。
- 最后,我们需要一个函数来将加权后的特征值与阈值进行比较,从而得出最终决定。这个函数通常是一个阶跃函数,即当输入大于某个阈值时返回 1(带伞),否则返回 0(不带伞)。
示例
假设我们有如下设置:
- “是否下雨”的权重是 0.5。
- “风力大小”的权重是 0.3。
- 阈值(bias)是 -0.7。
如果我们今天收到了这样的天气预报:“会下雨”(1)和“有风”(1),那么感知机将这样计算:
- 输入:[是否下雨, 风力大小] = [1, 1]
- 权重:[0.5, 0.3]
- 阈值(bias)= -0.7
计算过程如下:
(0.5 * 1) + (0.3 * 1) + (-0.7)
=0.5 + 0.3 - 0.7
=0.1
因为结果是正数(大于 0),根据我们的阶跃函数,这意味着我们应该带伞。
激活函数在深度学习中扮演着非常重要的角色。它们帮助神经网络从线性模型转变为非线性模型,使得网络能够学习到更加复杂的模式。下面我将以通俗易懂的方式为您解释激活函数的作用和几种常见的激活函数。
激活函数的作用
- 基本概念:
- 激活函数是神经网络中每个神经元(节点)用来决定输出的一个数学函数。它接收输入(通常是来自前一层神经元的加权和)并生成输出。
- 可以把激活函数想象成一个“开关”,它决定了神经元是否应该被激活(即是否应该传递信息到下一层)。
想象一下,你正在搭建一个模型来预测明天是否会下雨。在这个模型中,你可能需要考虑多种因素,比如温度、湿度、风速等。但这些因素之间的关系并不是简单的线性关系——比如说,当湿度达到一定程度时,下雨的概率会显著增加,但并不是湿度越高,下雨的概率就越高。
在神经网络中,每一层都会接收来自前一层的输入,并产生输出传递给下一层。如果没有激活函数,每一层的输出实际上都是输入的线性组合,整个神经网络就相当于一个大的线性模型。而我们知道现实世界中的许多问题并不是线性的,所以这就需要非线性变换来捕捉这些复杂的模式。
激活函数就像一个开关,它决定了神经元是否会被“激活”,即是否会对最终的输出产生影响。它将神经元的输入转换成输出信号,并引入了非线性特性。
简单的阶跃函数实现
def step_function(x):
y = x > 0
return y.astype(np.int)
-
类型转换:
return y.astype(np.int)
这一行将布尔数组y
转换为整数数组。在 NumPy 中,布尔值True
被视为1,False
被视为0。- 如果
y
是布尔值True
,则转换后为整数1。 - 如果
y
是布尔值False
,则转换后为整数0。
- 如果
示例说明
假设我们有一些输入值 x
:
- 如果
x = 1
,则y = x > 0
会得到True
,之后y.astype(np.int)
返回1
。 - 如果
x = -1
,则y = x > 0
会得到False
,之后y.astype(np.int)
返回0
。
对于数组的情况:
- 如果
x = np.array([-1, 0, 1])
,则y = x > 0
会得到布尔数组[False, False, True]
,最后y.astype(np.int)
返回整数数组[0, 0, 1]
。
NumPy 提供了一系列强大的函数来处理多维数组。下面是一些基本的多维数组运算函数及其说明:
1. **创建数组**
- `np.array()`: 创建一个数组。
- `np.zeros()`: 创建一个全零数组。
- `np.ones()`: 创建一个全一数组。
- `np.empty()`: 创建一个未初始化的数组。
- `np.arange()`: 创建一个等差数列。
- `np.linspace()`: 创建一个等间隔的数组。
- `np.eye()`: 创建单位矩阵。
- `np.diag()`: 创建对角矩阵。
- `np.random.rand()`: 创建一个随机数组(均匀分布)。
- `np.random.randn()`: 创建一个随机数组(正态分布)。
- `np.random.randint()`: 创建一个随机整数数组。
2. **数组操作**
- `np.reshape()`: 改变数组形状。
- `np.transpose()`: 转置数组。
- `np.ravel()`: 将多维数组展平成一维。
- `np.squeeze()`: 移除数组中的单维度条目。
- `np.expand_dims()`: 增加数组的维度。
- `np.tile()`: 重复数组。
- `np.repeat()`: 重复数组中的元素。
- `np.split()`: 沿着给定轴分割数组。
- `np.hsplit()`, `np.vsplit()`, `np.dsplit()`: 分别沿水平、垂直和深度方向分割数组。
- `np.concatenate()`: 沿着给定轴连接多个数组。
- `np.vstack()`, `np.hstack()`, `np.dstack()`: 分别沿垂直、水平和深度方向堆叠数组。
- `np.insert()`: 在指定位置插入值。
- `np.delete()`: 删除指定位置的值。
3. **数学运算**
- `np.add()`, `np.subtract()`, `np.multiply()`, `np.divide()`: 数学运算。
- `np.power()`: 幂运算。
- `np.mod()`: 模运算。
- `np.sqrt()`, `np.cbrt()`: 平方根和立方根。
- `np.exp()`, `np.log()`, `np.log10()`, `np.log2()`: 指数和对数函数。
- `np.sin()`, `np.cos()`, `np.tan()`: 三角函数。
- `np.arcsin()`, `np.arccos()`, `np.arctan()`: 反三角函数。
- `np.abs()`: 绝对值。
- `np.sign()`: 符号函数。
- `np.round()`: 四舍五入。
- `np.floor()`, `np.ceil()`: 向下取整和向上取整。
- `np.clip()`: 限制数组值在一定范围内。
- `np.sum()`, `np.prod()`: 求和和求积。
- `np.mean()`, `np.std()`, `np.var()`: 平均值、标准差、方差。
- `np.min()`, `np.max()`: 最小值和最大值。
- `np.argmin()`, `np.argmax()`: 返回最小值和最大值的索引。
4. **布尔运算**
- `np.equal()`, `np.not_equal()`, `np.greater()`, `np.less()`: 布尔比较。
- `np.logical_and()`, `np.logical_or()`, `np.logical_not()`: 布尔逻辑运算。
5. **线性代数**
- `np.dot()`, `np.matmul()`: 矩阵乘法。
- `np.linalg.inv()`: 矩阵逆。
- `np.linalg.eig()`: 特征值分解。
- `np.linalg.svd()`: 奇异值分解。
- `np.linalg.det()`: 矩阵行列式。
- `np.linalg.norm()`: 矩阵范数。
这些函数可以用于处理和分析多维数据,是数据分析和科学计算的重要工具。
回归问题是关于预测一个连续值的问题:房价预测,温度预测等等
二分类问题则是预测一个事件发生的概率,通常只会有两种结果,即“是”或“否”,“1”或“0”。:垃圾邮件检测等等
3层神经网络的实现见鱼书P58-P61
import numpy as np # 导入numpy库,用于数学运算
# 定义sigmoid函数,这是一个常用的激活函数,用于将线性变换的结果映射到(0,1)区间内
def sigmoid(x):
return 1 / (1 + np.exp(-x))
# 定义恒等函数,它只是返回输入值本身,没有做任何变换
def identity_function(x):
return x
# 初始化网络权重和偏置的函数
def init_network():
network = {} # 创建一个字典来存储网络参数
# 初始化第一层的权重矩阵W1和偏置向量b1
network['W1'] = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
network['b1'] = np.array([0.1, 0.2, 0.3])
# 初始化第二层的权重矩阵W2和偏置向量b2
network['W2'] = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
network['b2'] = np.array([0.1, 0.2])
# 初始化第三层的权重矩阵W3和偏置向量b3
network['W3'] = np.array([[0.1, 0.3], [0.2, 0.4]])
network['b3'] = np.array([0.1, 0.2])
return network # 返回包含所有参数的字典
# 前向传播函数
def forward(network, x):
# 从network字典中提取权重矩阵和偏置向量
W1, W2, W3 = network['W1'], network['W2'], network['W3']
b1, b2, b3 = network['b1'], network['b2'], network['b3']
# 第一层的前向传播
a1 = np.dot(x, W1) + b1 # 加权求和,x是输入向量
z1 = sigmoid(a1) # 通过sigmoid激活函数
# 第二层的前向传播
a2 = np.dot(z1, W2) + b2 # 使用第一层的输出z1作为输入
z2 = sigmoid(a2) # 通过sigmoid激活函数
# 第三层的前向传播
a3 = np.dot(z2, W3) + b3 # 使用第二层的输出z2作为输入
y = identity_function(a3) # 通过恒等函数作为输出层的激活函数
return y # 返回最终输出
# 初始化网络参数
network = init_network()
# 定义一个输入向量
x = np.array([1.0, 0.5])
# 进行前向传播计算
y = forward(network, x)
# 打印输出结果
print(y)
这段代码创建了一个简单的前馈神经网络,并使用一个输入向量进行了前向传播计算
Python中的继承
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
print("An animal makes a sound.")
def move(self):
print("The animal moves.")
class Dog(Animal):
def __init__(self, name, breed):#这行得先把父类的属性加进来,再添加子类特有的
super().__init__(name) # 这个括号里要有东西,和父类一致
self.breed = breed # 新增一个属性
def speak(self): # 重写父类的方法
print(f"{self.name} says Woof!")
def fetch_stick(self): # 新增一个方法
print(f"{self.name} fetched a stick!")
def wag_tail(self): # 再新增一个方法
print(f"{self.name} wags tail.")
# 创建一个 Dog 实例
my_dog = Dog("Buddy", "Golden Retriever")#对应子类的形参
# 调用 Dog 类的方法
my_dog.speak() # 输出: Buddy says Woof!
my_dog.fetch_stick() # 输出: Buddy fetched a stick!
my_dog.wag_tail() # 输出: Buddy wags tail.
# 调用继承自 Animal 类的方法
my_dog.move() # 输出: The animal moves.
将实例用做属性
# 定义 Engine 类,代表汽车的引擎
class Engine:
# 构造函数,接收一个参数 capacity 并将其保存为实例变量
def __init__(self, capacity):
self.capacity = capacity # 引擎的排量
# 启动引擎的方法
def start(self):
print(f"The engine with {self.capacity}L capacity is starting.") # 输出引擎启动的信息
# 停止引擎的方法
def stop(self):
print(f"The engine with {self.capacity}L capacity has stopped.") # 输出引擎停止的信息
# 定义 Car 类,代表一辆完整的汽车
class Car:
# 构造函数,接收 make, model 和 engine 三个参数
def __init__(self, make, model, engine):
self.make = make # 汽车的品牌
self.model = model # 汽车的型号
self.engine = engine # Engine 类的实例作为 Car 类的一个属性
self.is_running = False # 标记引擎是否正在运行
# 启动汽车引擎的方法
def start_engine(self):
if not self.is_running: # 如果引擎还没有启动
self.engine.start() # 调用 Engine 类的 start 方法
self.is_running = True # 标记引擎已启动
# 停止汽车引擎的方法
def stop_engine(self):
if self.is_running: # 如果引擎正在运行
self.engine.stop() # 调用 Engine 类的 stop 方法
self.is_running = False # 标记引擎已停止
# 创建一个 Engine 实例,此时这个engine为实例,然后作为上面类中的属性
engine = Engine(2.0) # 创建一个排量为 2.0 升的引擎实例,
# 创建一个 Car 实例,并将 engine 作为参数传入
car = Car("Toyota", "Corolla", engine) # 创建一个 Toyota Corolla 汽车实例,并关联一个引擎
# 启动汽车引擎
car.start_engine() # 输出: The engine with 2.0L capacity is starting.
# 停止汽车引擎
car.stop_engine() # 输出: The engine with 2.0L capacity has stopped.
以下是自己写的一个课后习题,运用了将实例作为属性:
# 定义 Car 类
class Car:
# 构造函数,接收 type 和 money 作为参数
def __init__(self, type, money):
self.type = type # 设置类型属性
self.money = money # 设置价格属性
# 定义 Battery 类
class Battery:
# 构造函数,接收 batterycape 作为参数
def __init__(self, batterycape):
self.batterycape = batterycape # 设置电池容量属性
# 升级电池容量的方法
def upgrade(self):
if self.batterycape < 65: # 如果电池容量小于 65
self.batterycape = 65 # 将电池容量升级到 65
print(f'充电中-------充电完成') # 输出升级信息
# 显示电池容量和里程数的方法
def range(self):
print(f'当前电池容量为:{self.batterycape}') # 输出当前电池容量
print(f'你的里程数是{self.batterycape * 34}千米') # 计算并输出里程数
# 定义 EleCar 类,继承自 Car 类
class EleCar(Car):
# 构造函数,接收 type, money 和 batterycape 作为参数
def __init__(self, type, money, batterycape):
super().__init__(type, money) # 调用父类 Car 的构造函数
self.batterycape = batterycape # 这个地方将实参传进来了
self.battery = Battery(self.batterycape) # 创建 Battery 类的实例,并传入电池容量,很巧妙
# 创建 EleCar 类的一个实例
kk = EleCar('dianche', '1000', 34) # 创建一辆电动汽车,类型为 'dianche',价格为 '1000',初始电池容量为 34
# 调用 Battery 实例的方法
kk.battery.range() # 输出当前电池容量和里程数
kk.battery.upgrade() # 升级电池容量
kk.battery.range() # 再次输出当前电池容量和里程数