分类猫和狗的图片

使用一个相机采集图片(12M像素), RGB图片有36M元素, 使用100大小的单隐藏层MLP, 模型有3.6B元素, 远多于世界上所有猫和狗总数(900M狗, 600M猫), 所以如果采用原始的MLP解决需要16亿的参数, 那么卷积神经网络提供了一个新的解决办法

两个原则

  • 平移不变性: 不论分类是在那个地方看应当都是差不多的
  • 局部性: 只需要观察一部分数据, 不需要观察全局的数据

全联接层到卷积层

将图片表示到矩阵
  1. 将输入和输出变形为矩阵(宽度, 高度), 因为需要保留图片信息
  2. 将权重变形为4-D张量(h, w), 到(h’, w’)
    hi,j=∑k,lwi,j,k,lxk,l=∑a,bvi,j,a,bxi+a,j+b h_{i,j} = \sum_{k,l}w_{i,j,k,l}x_{k,l} = \sum_{a,b}v_{i,j,a,b}x_{i+a,j+b} hi,j​=k,l∑​wi,j,k,l​xk,l​=a,b∑​vi,j,a,b​xi+a,j+b​
    vvv是www的重新索引(排列)使得vi,j,a,b=wi,j,i+a,j+bv_{i,j,a,b}=w_{i,j,i+a,j+b}vi,j,a,b​=wi,j,i+a,j+b​
    hi,jh_{i,j}hi,j​是输出, xxx代表输入, www代表之前全联接层的权重(4维)
应用平移不变性

x的平移导致h的平移hi,j=∑a,bvi,j,a,bxi+a,j+bh_{i,j}=\sum_{a,b}v_{i,j,a,b}x_{i+a,j+b}hi,j​=∑a,b​vi,j,a,b​xi+a,j+b​
v不应该依赖(i, j)
解决方案: vi,j,a,b=va,bv_{i,j,a,b}=v_{a,b}vi,j,a,b​=va,b​
hi,j=∑a,bva,bxi+a,j+b h_{i,j} = \sum_{a,b}v_{a,b}x_{i+a,j+b} hi,j​=a,b∑​va,b​xi+a,j+b​
这就是二维的交叉相关

应用局部性

hi,j=∑a,bva,bxi+a,j+b h_{i,j} = \sum_{a,b}v_{a,b}x_{i+a,j+b} hi,j​=a,b∑​va,b​xi+a,j+b​
当评估hi,jh_{i,j}hi,j​时, 我们不应该用远离xi,jx_{i,j}xi,j​的参数, 解决方案, 当∣a∣,∣b∣>Δ|a|, |b| > \Delta∣a∣,∣b∣>Δ时, 使得va,b=0v_{a,b}=0va,b​=0
hi,j=∑a=−ΔΔ∑b=−ΔΔva,bxi+a,j+b h_{i,j}=\sum_{a=-\Delta}^{\Delta}\sum_{b=-\Delta}^{\Delta}v_{a,b}x_{i+a,j+b} hi,j​=a=−Δ∑Δ​b=−Δ∑Δ​va,b​xi+a,j+b​

卷积层

二维交叉相关

在这里插入图片描述

  • Input: 输入
  • Kernel: 卷积核, 核窗口
  • Output: 输出

通过核窗口不断平移扫描输入的数据, 最终得到输出, 这就是二维交叉相关

二维卷积层

在这里插入图片描述

  1. 输入X:nh∗nwX: n_h * n_wX:nh​∗nw​, 高 * 宽的矩阵
  2. 核W:kn∗kwW: k_n * k_wW:kn​∗kw​
  3. 偏差b∈Rb \in \Rb∈R
  4. 输出Y:(nh−kn+1)∗(nw−kw+1)Y: (n_h - k_n + 1) * (n_w - k_w + 1)Y:(nh​−kn​+1)∗(nw​−kw​+1)
    Y=X∗W+bY = X * W + bY=X∗W+b
    WWW和bbb是可学习参数
不同卷积核

不同的卷积核所学习(提取)的特征是不同的
在这里插入图片描述

交叉相关和卷积

二维交叉相关
yi,j=∑a=1h∑b=1wwa,bxi+a,j+b y_{i,j} = \sum_{a=1}^h\sum_{b=1^w}w_{a,b}x_{i+a,j+b} yi,j​=a=1∑h​b=1w∑​wa,b​xi+a,j+b​
二维卷积
yi,j=∑a=1h∑b=1ww−a,−bxi+a,j+b y_{i,j}=\sum_{a=1}^h\sum_{b=1}^ww_{-a,-b}x_{i+a,j+b} yi,j​=a=1∑h​b=1∑w​w−a,−b​xi+a,j+b​
由于对称性, 在实际中没有区别, 卷积的区别在于w−a,−bw_{-a,-b}w−a,−b​, 实际是反着(镜面)来的

一维和三维交叉相关

一维

yi=∑a=1hwaxi+a y_i = \sum_{a=1}^hw_ax_{i+a} yi​=a=1∑h​wa​xi+a​
文本, 语言, 时序序列

三维

yi,j,k=∑a=1h∑b=1w∑c=1dwa,b,cxi+a,j+b,k+c y_{i,j,k} = \sum_{a=1}^h\sum_{b=1}^w\sum_{c=1}^dw_{a,b,c}x_{i+a,j+b,k+c} yi,j,k​=a=1∑h​b=1∑w​c=1∑d​wa,b,c​xi+a,j+b,k+c​
视频, 医学图像, 气象地图

总结

  • 卷积层将输入和核矩阵进行交叉相关, 加上偏移后得到输出
  • 核矩阵和偏移是可学习的参数
  • 核矩阵的大小是超参数

代码实现

互相关运算

import torch
from torch import nn
from d2l import torch as d2l

def corr2d(X, K):
	"""计算互相关运算
	@param X: 输入
	@param K: 核
	"""
	# 行数和列数
	h, w = K.shape
	# 输出的高=输入的高 - 核的高 + 1, 输出的宽=输入的宽 - 核的宽 + 1, 
	Y = torch.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1))
	for i in range(Y.shape[0]):
		for j in range(Y.shape[1]):
			# 遍历所有的X的数据, 然后不断偏移和核矩阵做点积
			Y[i, j] = (X[i:i + h, j:j + w] * K).sum()
	return Y

验证互相关运算

X = torch.tensor([[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]])
K = torch.tensor([[0.0, 1.0], [2.0, 3.0]])
corr2d(X, K)
# output: tensor([[19, 25], [37, 23]])

卷积层

class Conv2D(nn.Module):
	def __init__(self, kernel_size):
		super().__init__()
		# 卷积核是可学习的 kernel_size * kernel_size的矩阵
		self.weight = nn.Paramter(torch.rank(kernel_size))
		self.bias = nn.Parameter(torch.zeros(1))
	
	def forward(self, x):
		return corr2d(x, self.weight) + self.bias

学习X和Y生成卷积核

conv2d = nn.Conv2d(1, 1, kernel_size=(1, 2), bias=False)

# reshape(批量大小数, 通道数量, , )
X = X.reshape((1, 1, 6, 8))
Y = Y.reshape((1, 1, 6, 7))

for i in range(10):
	Y_hat = conv2d(X)
	# 使用均方差
	l = (Y_hat - Y) ** 2
	conv2d.zero_grad()
	l.sum().backward()
	conv2d.weight.data[:] -= 3e-2 * conv2d.weight.grad
	if (i + 1) % 2 == 0:
		print(f'batch {i + 1}, loss {l.sum():.3f}')

更多推荐