一.边缘检测示例
1.电脑如何检测图像的垂直边缘
一个灰度图像,要检测其中的边缘,可以使用一个三列不同数据(同列数字相同)组成的过滤器(在科研论文中会称之为核)
卷积运算用“ * ”表示
最后卷积后输出的图像上每一个像素的数值都由过滤器在原始图像上滚动乘积和获得
2.为什么这样能进行垂直边缘检测呢?
(此处边缘的像素看起来很厚是因为该数据较小,当数据足够大的时候,检测结果较好)
3.更多的边缘检测
(1)颜色翻转的检测对比
过滤器也可以检测由亮到暗的边缘
在这个图里的卷积输出结果来看第二行第一个30,表明检测器在这里找到了一个很强的正边界(上亮下暗)
右边的-30表明图像在这里找到了一个很强的负边界(上暗下亮)
第二行的10表明检测器检测到了左边正边界一部分,右边负边界一部分
4.过滤器的选择
unamed filter
sobel filter 优点:给中间行赋予更大权重使之更加稳定
scharr 过滤器
这些过滤器随机旋转90度就可以检测水平边缘了
残差神经网络
残差网络(ResNet)是使用了残差结构的网络
示例1:
🎆
激活函数输出结果(a^[l])→linear(加权矩阵*a^[l]+偏置)→relu(获得a^[l+1])→linear→relu→a^[l+2]
从a^[l]→a^[l+2]的流程叫做这层组的主路径
在残差网格中,a^[l]会往前复制,加到第二个relu前面,此时这个叫做快捷路径
由于a^[l]的加入
$$ a^[l+2]=g(z^[l+2]) 变成a^[l+2]=g(z^[l+2]+a^[l]) 【残差块】 $$
如果a[l]加入到linear之前,导致每一个节点都应用一个线性方程和relu,所以一般加入到线性之后relu之前
有时快捷路径(short path)叫跳跃连接(skip connection)
ResNet就是通过大量的残差块,把他们堆叠起来,形成一个深层网络
未使用ResNet的网络随着神经网络层数变多,性能会回弹变差,使用ResNet就避免了这种情况
原因如下:
1. 传统深层网络的问题:梯度消失与网络退化
(1) 梯度消失/爆炸
- 深层网络中,反向传播时梯度需要逐层传递,若网络过深:
- 梯度消失:权重更新量趋近于零,浅层参数无法有效更新。
- 梯度爆炸:权重更新量过大,导致训练不稳定。
- 缓解方法:批量归一化(BatchNorm)、权重初始化(如He初始化)等,但无法彻底解决深层网络训练困难。
(2) 网络退化(Degradation)
- 现象:随着网络层数增加,训练集上的准确率反而下降(如56层网络比20层更差)。
- 本质原因:并非过拟合,而是深层网络难以学习到有效的恒等映射(Identity Mapping),导致浅层网络的表达能力被破坏。
2. ResNet 的核心思想:残差学习
(1) 残差块(Residual Block)
ResNet 的核心单元是残差块,其结构如下:
python
复制引用
输出 = 输入 + 非线性变换(输入)
- 数学表达:[ y = F(x) + x ] 其中:
- (x):输入
- (F(x)):非线性变换(如多个卷积层)
- (y):输出
(2) 跳跃连接(Skip Connection)
- 作用:直接将输入 (x) 绕过非线性变换层,与 (F(x)) 相加。
- 优势:
- 网络可以轻松学习“残差”(F(x) = y - x),而非完整的映射 (y = H(x))。
- 若最优映射接近恒等变换(即 (H(x) \approx x)),网络只需将 (F(x)) 逼近零,比直接学习 (H(x)) 更容易。
(3) 梯度传播优化
- 梯度直接回传:跳跃连接为梯度提供了一条“高速公路”,避免梯度在深层网络中消失。
- 实验验证:ResNet-152(152层)的训练误差低于ResNet-34(34层),证明残差学习有效解决了退化问题。
3. ResNet vs 传统网络:性能对比
网络类型 | 层数 | ImageNet Top-1 Acc | 退化现象 |
---|---|---|---|
普通网络(VGG) | 19层 | ~72% | 无 |
普通网络(Plain) | 56层 | 下降至~65% | 严重退化 |
ResNet | 152层 | ~78% | 无退化 |
4. 为什么传统网络无法解决退化问题?
- 恒等映射难以学习:传统网络需显式学习 (H(x) = x),但在深层中非线性层堆叠导致参数更新困难。
- 梯度衰减:反向传播时,梯度需经过所有层,深层网络的梯度可能趋近于零,浅层参数无法更新。
class ResidualBlock(tf.keras.Model):
def __init__(self, filters):
super().__init__()
self.conv1 = layers.Conv2D(filters, 3, padding='same', activation='relu')
self.conv2 = layers.Conv2D(filters, 3, padding='same')
self.bn = layers.BatchNormalization()
def call(self, x):
residual = x
x = self.conv1(x)
x = self.bn(x)
x = self.conv2(x)
x = layers.add([x, residual]) # 跳跃连接
return tf.nn.relu(x)
在深度学习模型中,self.bn = layers.BatchNormalization()
表示创建了一个批标准化(Batch Normalization)层,用于对神经网络的中间输出进行标准化处理。以下是详细解释:
1. 批标准化(Batch Normalization)的作用
批标准化是一种广泛使用的技术,主要解决以下问题:
- 内部协变量偏移(Internal Covariate Shift):神经网络在训练时,每一层的输入分布会因参数更新而不断变化,导致训练不稳定。批标准化通过标准化每层的输入,使其分布更稳定。
- 加速训练:减少梯度消失/爆炸问题,允许使用更大的学习率。
- 正则化效果:轻微减少对 Dropout 等正则化技术的依赖。
2. 代码解析
python
复制引用
self.bn = layers.BatchNormalization()
- 这是 TensorFlow/Keras 中的一个层,用于在模型中插入批标准化操作。
- 输入:上一层的输出(如卷积层、全连接层)。
- 操作:
- 训练阶段:对当前批次的每个特征通道计算均值(
mean
)和方差(variance
),然后标准化输入为(x - mean) / sqrt(variance + epsilon)
。 - 推理阶段:使用训练时累积的移动平均均值和方差(而非当前批次的统计量)。
- 训练阶段:对当前批次的每个特征通道计算均值(
3. 典型使用场景
通常插入在线性层(如 Dense、Conv2D)和激活函数(如 ReLU)之间:
python
复制引用
x = layers.Dense(128)(x)
x = self.bn(x) # 批标准化
x = layers.Activation("relu")(x)
或:
python
复制引用
x = layers.Conv2D(64, 3, padding="same")(x)
x = self.bn(x)
x = layers.ReLU()(x)
4. 关键参数(可选)
在定义时可通过参数调整行为:
momentum
(默认0.99
):控制移动均值和方差的更新速度。epsilon
(默认1e-3
):防止除以零的小常数。axis
(默认1
):指定需要标准化的维度(例如,对通道维度标准化)。
5. 注意事项
- 训练与推理的区别:在训练时,模型需明确区分模式(如
model.fit()
自动处理);在推理时,需设置training=False
。 - 与 Dropout 的配合:批标准化本身有轻微正则化效果,可减少 Dropout 的使用。
- 小批量数据问题:若批次过小(如 batch_size=1),移动平均统计量可能不准确。
6. 示例代码
python
复制引用
import tensorflow as tf
from tensorflow.keras import layers, Model
class MyModel(Model):
def __init__(self):
super(MyModel, self).__init__()
self.conv = layers.Conv2D(32, 3)
self.bn = layers.BatchNormalization() # 批标准化层
self.relu = layers.ReLU()
def call(self, x, training=False):
x = self.conv(x)
x = self.bn(x, training=training) # 注意传递 training 参数
x = self.relu(x)
return x
# 使用模型
model = MyModel()
总结
layers.BatchNormalization()
是一种提升模型训练速度和稳定性的关键层,通过对中间激活值进行标准化,使网络更容易优化。理解其在不同阶段的行为(训练/推理)是正确使用的关键。