CNN
卷积神经网络(Convolutional Neural Networks, CNN)是一类包含卷积计算且具有深度结构的前馈神经网络(Feedforward Neural Networks),是深度学习(deep learning)的代表算法之一。卷积神经网络具有表征学习(representation learning)能力,能够按其阶层结构对输入信息进行平移不变分类(shift-invariant classification),因此也被称为“平移不变人工神经网络(Shift-Invariant Artificial Neural Networks, SIANN)”[3]。
卷积神经网络仿造生物的视知觉(visual perception)机制构建,可以进行监督学习和非监督学习,其隐含层内的卷积核参数共享和层间连接的稀疏性使得卷积神经网络能够以较小的计算量对格点化(grid-like topology)特征,例如像素和音频进行学习、有稳定的效果且对数据没有额外的特征工程(feature engineering)要求。
以著名的pyTorch Tutorials示例代码为例:
class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.conv1 = nn.Sequential( # input shape (1, 28, 28)
nn.Conv2d(
in_channels=1, # input height
out_channels=16, # n_filters
kernel_size=5, # filter size
stride=1, # filter movement/step
padding=2, # if want same width and length of this image after Conv2d, padding=(kernel_size-1)/2 if stride=1
), # output shape (16, 28, 28)
nn.ReLU(), # activation
nn.MaxPool2d(kernel_size=2), # choose max value in 2x2 area, output shape (16, 14, 14)
)
self.conv2 = nn.Sequential( # input shape (16, 14, 14)
nn.Conv2d(16, 32, 5, 1, 2), # output shape (32, 14, 14)
nn.ReLU(), # activation
nn.MaxPool2d(2), # output shape (32, 7, 7)
)
self.out = nn.Linear(32 * 7 * 7, 10) # fully connected layer, output 10 classes
def forward(self, x):
x = self.conv1(x)
x = self.conv2(x)
x = x.view(x.size(0), -1) # flatten the output of conv2 to (batch_size, 32 * 7 * 7)
output = self.out(x)
return output, x # return x for visualization
输入层
卷积神经网络的输入层可以处理多维数据,使用梯度下降进行学习,卷积神经网络的输入特征需要进行标准化处理。在将学习数据输入卷积神经网络前,需在通道或时间/频率维对输入数据进行归一化,若输入数据为像素,也可将分布于【0,255】的原始像素值归一化至【0,1】区间。输入特征的标准化有利于提升卷积神经网络的学习效率和表现。
隐含层
卷积神经网络的隐含层包含卷积层、池化层和全连接层3类常见构筑,在一些更为现代的算法中可能有Inception模块、残差块(residual block)等复杂构筑。在常见构筑中,卷积层和池化层为卷积神经网络特有。常见构筑在隐含层中的顺序通常为:输入-卷积层-池化层-全连接层-输出。
- 卷积层参数("self.conv1")——卷积层参数包括卷积核大小、步长和填充,三者共同决定了卷积层输出特征图的尺寸,是卷积神经网络的超参数[1]。其中卷积核大小可以指定为小于输入图像尺寸的任意值,卷积核越大,可提取的输入特征越复杂[1]。
公式:height = (H+2*P-F)/S+1;width = (W+2*P-F)/S+1;H、W分别指输入图的尺寸,F为卷积核大小,S表示步长,P表示填充。
如上例:h、w=28,F=5,S=1。height ,width= (28+2*2-5)/1+1 = 28
- 激励函数(activation function,"nn.ReLU()")— 卷积层中包含激励函数以协助表达复杂特征,卷积神经网络通常使用线性整流函数(Rectified Linear Unit, ReLU),激励函数操作通常在卷积核之后。
池化层(pooling layer)
在卷积层进行特征提取后,输出的特征图会被传递至池化层进行特征选择和信息过滤。池化层包含预设定的池化函数,其功能是将特征图中单个点的结果替换为其相邻区域的特征图统计量。池化层选取池化区域与卷积核扫描特征图步骤相同,由池化大小、步长和填充控制 [1] 。
全连接层(fully-connected layer)
卷积神经网络中的全连接层等价于传统前馈神经网络中的隐含层。全连接层通常搭建在卷积神经网络隐含层的最后部分,并只向其它全连接层传递信号。特征图在全连接层中会失去3维结构,被展开为向量并通过激励函数传递至下一层。
输出层
卷积神经网络中输出层的上游通常是全连接层,因此其结构和工作原理与传统前馈神经网络中的输出层相同。对于图像分类问题,输出层使用逻辑函数或归一化指数函数(softmax function)输出分类标签 [16] 。在物体识别(object detection)问题中,输出层可设计为输出物体的中心坐标、大小和分类 [16] 。在图像语义分割中,输出层直接输出每个像素的分类结果 [16] 。
RNN
循环神经网络,Recurrent Neural Network。神经网络是一种节点定向连接成环的人工神经网络。这种网络的内部状态可以展示动态时序行为。不同于前馈神经网络的是,RNN可以利用它内部的记忆来处理任意时序的输入序列,这让它可以更容易处理如不分段的手写识别、语音识别等。
RNN的假设——事物的发展是按照时间序列展开的,即前一刻发生的事物会对未来的事情的发展产生影响。所以在处理过程中,每一刻的输出是带着之前输出值加权之后的结果。
但是,RNN对于短期记忆的模型效果很好,却无法进行长期记忆的输出,因为权重累加过于庞大,可能导致结果是真、运算效率低下。所以LSTM应运而生。
整个单元内主要包含异或门和与门。
1 异或 1 = 0 认为是相同的信息,舍弃
1 与 0 = 1 将不同的信息叠加
通过这两部运算就能减少我们的数据量,将重复信息遗忘,将未知信息记录下来,将结果更新之后,再输出。
class RNN(nn.Module):
def __init__(self):
super(RNN, self).__init__()
self.rnn = nn.LSTM(
input_size=INPUT_SIZE,
hidden_size=64,
num_layers=1,
batch_first=True # input & output will has batch size as 1s dimension. e.g. (batch, time_step, input_size)
)
self.out = nn.Linear(64,10)
def forward(self, x):
# x shape (batch, time_step, input_size)
# r_out shape (batch, time_step, output_size)
# h_n shape (n_layers, batch, hidden_size)
# h_c shape (n_layers, batch, hidden_size)
r_out, (h_n, h_c) = self.rnn(x, None) # None represents zero initial hidden state
# choose r_out at the last time step
out = self.out(r_out[:, -1, :])
return out
RNN Regressor
class RNN(nn.Module):
def __init__(self):
super(RNN, self).__init__()
self.rnn = nn.RNN(
input_size=INPUT_SIZE,
hidden_size=32, # rnn hidden unit
num_layers=1, # number of rnn layer
batch_first=True, # input & output will has batch size as 1s dimension. e.g. (batch, time_step, input_size)
)
self.out = nn.Linear(32, 1)
def forward(self, x, h_state):
# x (batch, time_step, input_size)
# h_state (n_layers, batch, hidden_size)
# r_out (batch, time_step, hidden_size)
r_out, h_state = self.rnn(x, h_state)
outs = [] # save all predictions
for time_step in range(r_out.size(1)): # calculate output for each time step
outs.append(self.out(r_out[:, time_step, :]))
return torch.stack(outs, dim=1), h_state
# instead, for simplicity, you can replace above codes by follows
# r_out = r_out.view(-1, 32)
# outs = self.out(r_out)
# outs = outs.view(-1, TIME_STEP, 1)
# return outs, h_state
# or even simpler, since nn.Linear can accept inputs of any dimension
# and returns outputs with same dimension except for the last
# outs = self.out(r_out)
# return outs
timestep
是序列的长度,经过多少个时间步得到输出