⚠️ Alpha内测版本警告:此为早期内部构建版本,尚不完整且可能存在错误,欢迎大家提Issue反馈问题或建议。
Skip to content

第24章卷积神经网络

习题24.1

  设有输入矩阵X=[xij]I×J,核矩阵W=[wmn]M×N,满足MI,NJ,则称以下运算为二维数学卷积:

Y=WX

产生输出矩阵Y=[ykl]K×L,其中

ykl=m=1Mn=1Nwmnxim+1,jn+1K=IM+1,L=JN+1

证明数学卷积和机器学习卷积有以下关系:

WX=rot180(W)X

这里表示数学卷积,表示机器学习卷积,rot180()表示对矩阵的180度旋转。

解答:

解答思路:

  1. 给出机器学习二维卷积的定义
  2. 计算rot180(W)X输出矩阵Y
  3. 验证YY相等

解答步骤:

第1步:给出机器学习二维卷积的定义

  根据书中第24.1.2节的定义24.1的二维卷积的定义:

定义24.1(二维卷积) 给定一个 I×J 输入矩阵 X=[xi,j]I×J,一个 M×N 核矩阵 W=[wm,n]M×N,满足 MI,NJ。让核矩阵在输入矩阵上从左到右再从上到下按顺序滑动,在滑动的每一个位置,核矩阵与输入矩阵的一个子矩阵重叠。求核矩阵与每一个子矩阵的内积,产生一个 K×L 输出矩阵 Y=[yk,l]K×L,称此运算为卷积(convolution)或二维卷积。写作

(24.4)Y=WX

其中, Y=[yk,l]K×L

(24.5)yk,l=m=1Mn=1Nwm,nxk+m1,l+n1

其中,k=1,2,,K, l=1,2,,L, K=IM+1, L=JN+1

第2步:计算rot180(W)X输出矩阵Y

  令W=rot180(W)=[wm,n]M×N=[wMm+1,Nn+1]M×N,则对于rot180(W)X输出矩阵Y=[yk,l]K×L有:

yk,l=m=1Mn=1Nwm,nxk+m1,l+n1=m=1Mn=1NwMm+1,Nn+1xk+m1,l+n1

  令p=Mm+1,且当m=1时,p=M,当m=M时,p=1;令q=Nn+1,且当n=1q=N,当n=Nq=1,则:

yk,l=p=M1q=N1wp,qxk+Mp,l+Nq=p=1Mq=1Nwp,qxk+Mp,l+Nq

第3步:验证YY相等

  对于Y=WX=[ykl]K×L,由题目可知:

yk,l=m=1Mn=1Nwm,nxim+1,jn+1K=IM+1,L=JN+1

可令i=k+M1,j=l+N1,则

im+1=k+Mmjn+1=l+Nn

可得:

yk,l=m=1Mn=1Nwmnxk+Mm,l+Nn

  因此,WX=Y=Y=rot180(W)X,故原命题得证。

习题24.2

  假设有矩阵

A=[3201021220032312],B=[212003002]

其中,A是输入矩阵,B是核矩阵,可以求得数学卷积BA

BA=[6786130413154742101661448151561700109312004624]

试求数学卷积AB,并验证数学卷积满足交换律。

解答:

解答思路:

  1. 给出数学卷积的定义
  2. 给出二维数学卷积的定义
  3. 计算数学卷积AB
  4. 验证数学卷积满足交换律

解答步骤:

第1步:数学卷积的定义

  根据书中第24.1.2节的数学卷积的定义:

  在数学中,卷积(convolution)是定义在两个函数上的运算,表示用其中一个函数对另一个函数的形状进行的调整。这里考虑一维卷积。设 fg 是两个可积的实值函数,则积分

+f(τ)g(tτ)dτ

  定义了一个新的函数 h(t),称为 fg 的卷积,记作

h(t)=(fg)(t)=+f(τ)g(tτ)dτ

其中,符号 表示卷积运算。

第2步:二维数学卷积的定义

  见习题24.1中二维数学卷积:

Y=WX

其中输入矩阵X=[xij]I×J,核矩阵W=[wmn]M×N,满足MI,NJ,产生输出矩阵Y=[ykl]K×L,其中

ykl=m=1Mn=1Nwmnxim+1,jn+1K=IM+1,L=JN+1

第3步:计算数学卷积AB

  根据定义,计算AB

AB=[6786130413154742101661448151561700109312004624]

第4步:验证数学卷积满足交换律

  不妨设

h(t)=(gf)(t)=+g(τ)f(tτ)dτ

  令 tτ=λdλ=dτ,且当τ+时,λ;当τ时,λ+,则:

h(t)=+g(tλ)f(λ)dλ=+g(tλ)f(λ)dλ

  因此,(gf)(t)=(fg)(t),即数学卷积满足交换律,原命题得证。

习题24.3

  验证机器学习卷积(互相关)不满足交换律。

解答:

解答思路:

  1. 给出机器学习卷积定义
  2. 计算XW
  3. 验证XWWX不相等

解答步骤:

第1步:机器学习卷积定义

  根据书中第24章的本章概要的机器学习卷积的定义:

给定输入矩阵X=[xij]I×J,核矩阵W=[wmn]M×N。让核矩阵在输入矩阵上按顺序滑动,(二维)卷积是定义在核矩阵与输入矩阵的子矩阵的内积,产生输出矩阵Y=[ykl]K×L

Y=WX

其中,Y=[ykl]K×Lykl=m=1Mn=1Nwm,nxk+m1,l+n1

第2步:计算XW

  设XW的输出矩阵为Y=[ykl]K×L,则

ykl=i=1Ij=1Jxi,jwk+i1,l+j1

其中k=1,2,,K, l=1,2,,L, K=MI+1, L=NJ+1

  令p=k+i1,当i=1时,p=k,当i=I时,p=k+I1;令q=l+j1,当j=1q=l,当j=Jq=l+J1,则

ykl=p=kk+I1q=ll+J1wp,qxpk+1,ql+1

第3步:验证XWWX不相等

  综上,Y=[ykl]K×LY=[ykl]K×L,即 XWWX,原命题得证。

习题24.4

  CNN也可以用于一维数据的处理,求图24.22所示的一维卷积。

24-4.png

解答:

解答思路:

  1. 根据二维卷积的定义,写出一维卷积的定义
  2. 计算一维卷积的输出矩阵

解答步骤:

第1步:根据二维卷积的定义,写出一维卷积的定义

  给定一个I×1输入矩阵XM×1核矩阵W,可将它们视作第2维度为1的二维矩阵,则产生的输出矩阵为

Y=WX=[yk,1]K×1

其中

yk,1=m=1Mwm,1xk+m1,1

其中,k=1,2,,K, K=IM+1

第2步:计算一维卷积的输出矩阵

  根据上述公式计算可得:

y1,1=m=13wm,1x1+m1,1=3×1+0×1+2×2=7y2,1=m=13wm,1x2+m1,1=0×1+2×1+2×2=6y3,1=m=13wm,1x3+m1,1=2×1+2×1+2×2=8y4,1=m=13wm,1x4+m1,1=2×1+2×1+1×2=2y5,1=m=13wm,1x5+m1,1=2×1+1×1+2×2=5

  一维卷积的输出矩阵为

Y=[76825]

习题24.5

  通过例24.2验证卷积运算不具有旋转可变性。假设对图像数据进行90度顺时针和逆时针旋转。

解答:

解答思路:

  1. 将输入矩阵X顺时针旋转90度,计算卷积核为W时的输出矩阵
  2. 将输入矩阵X逆时针旋转90度,计算卷积核为W时的输出矩阵
  3. 验证旋转之后产生的输出矩阵与未旋转产生的输出矩阵不相等

解答步骤:

  例24.2给定的输入矩阵X和核矩阵W

X=[3201021220032312],W=[212003002]

第1步:将输入矩阵X顺时针旋转90度,计算卷积核为W时的输出矩阵

  将输入矩阵X顺时针旋转90度,得:

Xrot90=rot90(X)=[2203302210102321]

  根据二维卷积定义,得到输出矩阵

Yrot90=WXrot90=[212003002][2203302210102321]=[1416178]

第2步:将输入矩阵X逆时针旋转90度,计算卷积核为W时的输出矩阵

  将输入矩阵X逆时针旋转90度,得:

Xrot90=rot-90(X)=[1232010122033022]

  根据二维卷积定义,得到输出矩阵:

Yrot90=WXrot90=[212003002][1232010122033022]=[1020517]

第3步:验证旋转之后产生的输出矩阵与未旋转产生的输出矩阵不相等

  由例24.2可知,

Y=WX=[212003002][3201021220032312]=[1118622]

  显然,YYrot90Yrot90,即卷积运算不具有旋转可变性。

习题24.6

  证明感受野的关系式(24.19)成立。

解答:

解答思路:

  1. 给出感受野的关系式
  2. 写出感受野递推形式的计算公式
  3. 用数学归纳法证明感受野关系式成立

解答步骤:

第1步:感受野的关系式

  根据书中第24.1.4节的感受野的关系式:

  考虑卷积神经网络全部由卷积层组成的情况,神经元的感受野的大小有以下关系成立。

(24.19)R(l)=1+j=1l(F(j)1)i=0j1S(i)

设输入矩阵和卷积核都呈正方形。R(l)×R(l) 表示第 l 层的神经元的感受野的大小,F(j)×F(j) 表示第 j 层的卷积核的大小,S(i) 表示第 i 层卷积的步幅,设 S(0)=1

第2步:写出感受野递推形式的计算公式

  每个卷积层的每个神经元只与上一层的一部分神经元相连,故我们可根据上一层卷积层情况推导出下一层的感受野,感受野递推形式的计算公式如下:

R(l)=R(l1)+(F(l)1)I(l)

其中,R(l)×R(l)R(l1)×R(l1)分别表示第ll1层的神经元的感受野的大小,F(j)×F(j) 表示第 j 层的卷积核的大小。I(l)表示第l层输出特征图的特征间的间隔,由I(l)=I(l1)Sl1,设I(0)=1

第3步:用数学归纳法证明感受野关系式成立

  当l=1时,R1=1+(F11)=F1,显然成立

  假设当 l=n 时,

R(n)=1+j=1n(F(j)1)i=0j1S(i)

  成立。

  当l=n+1时,

R(n+1)=R(n)+(F(n+1)1)In+1=R(n)+(F(n+1)1)InSn=R(n)+(F(n+1)1)In1Sn1Sn=R(n)+(F(n+1)1)I0S0S1Sn1Sn=R(n)+(F(n+1)1)i=0nS(i)=1+j=1n(F(j)1)i=0j1S(i)+(F(n+1)1)i=0nS(i)=1+j=1n+1(F(j)1)i=0j1S(i)

结合R(n)R(n+1)的关系式,可得到:

R(l)=1+j=1l(F(j)1)i=0j1S(i)

习题24.7

  设计一个基于CNN的自然语言句子分类模型。假设句子是单词序列,每个单词用一个实数向量表示。

解答:

解答思路:

  1. 给出自然语言句子分类模型的参考文献和相关的模型架构图
  2. 使用PyTorch编程实现模型

解答步骤:

第1步:给出自然语言句子分类模型的参考文献和相关的模型架构图

  根据Chen,Yahui的Convolutional neural network for sentence classification. MS thesis. University of Waterloo论文,该论文提出了一种基于CNN的自然语言句子分类模型,其模型架构图如下:

24-7.png

第2步:使用PyTorch编程实现模型

python
import time
import torch
from torch import nn, optim
from torch.utils.data import random_split, DataLoader
from torchtext.data import get_tokenizer, to_map_style_dataset
from torchtext.datasets import AG_NEWS
from torchtext.vocab import build_vocab_from_iterator
python
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
python
# 加载AG_NEWS数据集
train_iter, test_iter = AG_NEWS(root='./data')
python
# 定义tokenizer
tokenizer = get_tokenizer('basic_english')


# 定义数据处理函数
def yield_tokens(data_iter):
    for _, text in data_iter:
        yield tokenizer(text)


# 构建词汇表
vocab = build_vocab_from_iterator(yield_tokens(train_iter), specials=["<unk>"])
vocab.set_default_index(vocab["<unk>"])
python
# 将数据集映射到MapStyleDataset格式
train_dataset = list(to_map_style_dataset(train_iter))
test_dataset = list(to_map_style_dataset(test_iter))
# 划分验证集
num_train = int(len(train_dataset) * 0.9)
train_dataset, val_dataset = random_split(train_dataset, [num_train, len(train_dataset) - num_train])

text_pipeline = lambda x: vocab(tokenizer(x))
label_pipeline = lambda x: int(x) - 1
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")


def collate_batch(batch):
    label_list, text_list, offsets = [], [], [0]
    for (_label, _text) in batch:
        label_list.append(label_pipeline(_label))
        processed_text = torch.tensor(text_pipeline(_text), dtype=torch.int64)
        text_list.append(processed_text)
        offsets.append(processed_text.size(0))
    label_list = torch.tensor(label_list, dtype=torch.int64)
    offsets = torch.tensor(offsets[:-1]).cumsum(dim=0)
    text_list = torch.cat(text_list)
    return label_list.to(device), text_list.to(device), offsets.to(device)


BATCH_SIZE = 64
# 构建数据集的数据加载器
train_dataloader = DataLoader(train_dataset, batch_size=BATCH_SIZE,
                              shuffle=True, collate_fn=collate_batch)
valid_dataloader = DataLoader(val_dataset, batch_size=BATCH_SIZE,
                              shuffle=True, collate_fn=collate_batch)
test_dataloader = DataLoader(test_dataset, batch_size=BATCH_SIZE,
                             shuffle=True, collate_fn=collate_batch)
python
class CNN_Text(nn.Module):
    def __init__(self, vocab_size, embed_dim, class_num=4, dropout=0.5, kernel_size: list = None):
        super(CNN_Text, self).__init__()
        if kernel_size is None:
            kernel_size = [3, 4, 5]
        self.embedding = nn.EmbeddingBag(vocab_size, embed_dim, sparse=False)
        self.convs = nn.ModuleList(
            [nn.Conv1d(in_channels=1, out_channels=256, kernel_size=k) for k in kernel_size])
        self.fc = nn.Sequential(
            nn.Dropout(p=dropout),
            nn.Linear(256 * len(kernel_size), 256),
            nn.ReLU(),
            nn.Dropout(p=dropout),
            nn.Linear(256, class_num)
        )

    def forward(self, text, offsets):
        embedded = self.embedding(text, offsets)
        embedded = embedded.unsqueeze(0)
        embedded = embedded.permute(1, 0, 2)
        conv_outputs = []
        for conv in self.convs:
            conv_outputs.append(nn.functional.relu(conv(embedded)))
        pooled_outputs = []
        for conv_output in conv_outputs:
            pooled = nn.functional.max_pool1d(conv_output, conv_output.shape[-1]).squeeze(-1)
            pooled_outputs.append(pooled)
        cat = torch.cat(pooled_outputs, dim=-1)
        return self.fc(cat)
python
# 设置超参数
vocab_size = len(vocab)
embed_dim = 64
class_num = len(set([label for label, _ in train_iter]))
lr = 1e-3
dropout = 0.5
epochs = 10
python
# 创建模型、优化器和损失函数
model = CNN_Text(vocab_size, embed_dim, class_num, dropout).to(device)
optimizer = optim.Adam(model.parameters(), lr=lr)
criterion = nn.CrossEntropyLoss()
python
def train(dataloader):
    model.train()

    for label, text, offsets in dataloader:
        optimizer.zero_grad()
        predicted_label = model(text, offsets)
        loss = criterion(predicted_label, label)
        loss.backward()
        torch.nn.utils.clip_grad_norm_(model.parameters(), 0.1)
        optimizer.step()
python
def evaluate(dataloader):
    model.eval()
    total_acc, total_count = 0, 0

    with torch.no_grad():
        for label, text, offsets in dataloader:
            predicted_label = model(text, offsets)
            criterion(predicted_label, label)
            total_acc += (predicted_label.argmax(1) == label).sum().item()
            total_count += label.size(0)
    return total_acc / total_count
python
max_accu = 0
for epoch in range(1, epochs + 1):
    epoch_start_time = time.time()
    train(train_dataloader)
    accu_val = evaluate(valid_dataloader)
    print('-' * 59)
    print('| end of epoch {:3d} | time: {:5.2f}s | '
          'valid accuracy {:8.1f}% '.format(epoch,
                                            time.time() - epoch_start_time,
                                            accu_val * 100))
    print('-' * 59)
    if max_accu < accu_val:
        best_model = model
        max_accu = accu_val
-----------------------------------------------------------
| end of epoch   1 | time: 13.36s | valid accuracy     57.3% 
-----------------------------------------------------------
-----------------------------------------------------------
| end of epoch   2 | time: 10.13s | valid accuracy     77.8% 
-----------------------------------------------------------
-----------------------------------------------------------
| end of epoch   3 | time: 10.27s | valid accuracy     83.3% 
-----------------------------------------------------------
-----------------------------------------------------------
| end of epoch   4 | time: 10.70s | valid accuracy     85.4% 
-----------------------------------------------------------
-----------------------------------------------------------
| end of epoch   5 | time: 10.66s | valid accuracy     86.1% 
-----------------------------------------------------------
-----------------------------------------------------------
| end of epoch   6 | time: 10.63s | valid accuracy     86.5% 
-----------------------------------------------------------
-----------------------------------------------------------
| end of epoch   7 | time: 10.72s | valid accuracy     86.6% 
-----------------------------------------------------------
-----------------------------------------------------------
| end of epoch   8 | time: 10.75s | valid accuracy     86.6% 
-----------------------------------------------------------
-----------------------------------------------------------
| end of epoch   9 | time: 10.65s | valid accuracy     86.8% 
-----------------------------------------------------------
-----------------------------------------------------------
| end of epoch  10 | time: 11.39s | valid accuracy     86.5% 
-----------------------------------------------------------
python
# 在测试集上测试模型
test_acc = 0.0
with torch.no_grad():
    for label, text, offsets in test_dataloader:
        output = best_model(text, offsets)
        pred = output.argmax(dim=1)
        test_acc += (pred == label).sum().item()
test_acc /= len(test_dataset)

print(f"Test Acc: {test_acc * 100 :.1f}%")
Test Acc: 86.9%
python
ag_news_label = {1: "World",
                 2: "Sports",
                 3: "Business",
                 4: "Sci/Tec"}

def predict(text, text_pipeline):
    with torch.no_grad():
        text = torch.tensor(text_pipeline(text))
        output = best_model(text, torch.tensor([0]))
        return output.argmax(1).item() + 1
python
ex_text_str = """
Our younger Fox Cubs (Y2-Y4) also had a great second experience of swimming competition in February when they travelled 
over to NIS at the end of February to compete in the SSL Development Series R2 event. For students aged 9 and under 
these SSL Development Series events are a great introduction to competitive swimming, focussed on fun and participation 
whilst also building basic skills and confidence as students build up to joining the full SSL team in Year 5 and beyond.
"""
best_model = best_model.to("cpu")
print("This is a %s news" % ag_news_label[predict(ex_text_str, text_pipeline)])
This is a World news

习题24.8

  设有输入矩阵X和核矩阵W

X=[xij]=[x11x12x13x14x15x21x22x23x24x25x31x32x33x34x35x41x42x43x44x45],W=[wmn]=[w11w12w13w21w22w23w31w32w33]

有卷积Y=WX

Y=[ykl]=[y11y12y13y21y22y23y31y32y33]

YWYX,并具体地写出dykldwmndykldxij

解答:

解答思路:

  1. 给出二维卷积定义
  2. 计算 YWYX
  3. 计算 dykldwmndykldxij

解答步骤:

第1步:二维卷积定义

  根据书中第24章的本章概要的二维卷积的定义:

  给定输入矩阵X=[xij]I×J,核矩阵W=[wmn]M×N。让核矩阵在输入矩阵上按顺序滑动,(二维)卷积是定义在核矩阵与输入矩阵的子矩阵的内积,产生输出矩阵Y=[ykl]K×L

Y=WX

其中,Y=[ykl]K×L

ykl=m=1Mn=1Nwm,nxk+m1,l+n1

其中,k=1,2,,K,l=1,2,,L,K=IM+1,L=JN+1

第2步:计算 YWYX

  1. 计算 YW
YW=Ywm,n=k=1Kl=1Lyklwm,nYykl=k=1Kl=1L(wm,nxk+m1,l+n1)wm,nYykl=k=1Kl=1Lxk+m1,l+n1Yykl
  1. 计算 YX

根据二维卷积的定义,可得:

m=ik+1n=jl+1

则:

YX=Yxij=k=1Kl=1LyklxijYykl=k=1Kl=1L(wik+1,jl+1xij)xijYykl=k=1Kl=1Lwik+1,jl+1Yykl

第3步:计算 dykldwmndykldxij

  1. 计算 dykldwmn
dykldwmn=d(m=1Mn=1Nwm,nxk+m1,l+n1)dwmn=xk+m1,l+n1
  1. 计算 dykldxij

  首先计算 dykldxk+m1,l+n1

dykldxk+m1,l+n1=d(m=1Mn=1Nwm,nxk+m1,l+n1)dxk+m1,l+n1=wmn

  令i=k+m1,且当m=1时,i=k,当m=M时,i=k+M1;令j=l+n1,且当n=1时,j=l,当n=N时,j=l+N1

  则当 i[k,k+M1]j[l,l+N1]时,可得:

dykldxij=wmn=wik+1,il+1

  当 i[k,k+M1]j[l,l+N1]时,可得:

dykldxij=0

  综上,

dykldxij={wik+1,il+1,if i[k,k+M1]j[l,l+N1]0,otherwise

习题24.9

  设有输入矩阵X和核矩阵W

X=[x11x12x13x21x22x23x31x32x33],W=[w11w12w13w21w22w23w31w32w33]

验证rot180(W)X=rot180(X)W成立。

解答:

解答思路:

  1. 给出机器学习卷积的定义
  2. 计算rot180(W)X
  3. 计算rot180(X)W
  4. 验证rot180(W)Xrot180(X)W是否相等

解答步骤:

第1步:给出机器学习卷积的定义

  根据书中第24章的本章概要的二维卷积的定义:

  给定输入矩阵X=[xij]I×J,核矩阵W=[wmn]M×N。让核矩阵在输入矩阵上按顺序滑动,(二维)卷积是定义在核矩阵与输入矩阵的子矩阵的内积,产生输出矩阵Y=[ykl]K×L

Y=WX

其中,Y=[ykl]K×L

ykl=m=1Mn=1Nwm,nxk+m1,l+n1

其中,k=1,2,,K,l=1,2,,L,K=IM+1,L=JN+1

第2步:计算rot180(W)X

  由题意已知:

rot180(W)=[wm,n]=[w4m,4n]

  由机器学习卷积定义,可得:

Y=rot180(W)X=[ykl]=m=13n=13wm,nxk+m1,l+n1=m=13n=13w4m,4nxk+m1,l+n1

第3步:计算rot180(X)W

  由题意已知:

rot180(X)=[xi,j]=[x4i,4j]

  由机器学习卷积定义,可得:

Y=rot180(X)W=[ykl]=i=13j=13xi,jwk+i1,l+j1=i=13j=13x4i,4jwk+i1,l+j1

第4步:验证rot180(W)Xrot180(X)W是否相等

  由上述计算可知:

Y=m=13n=13w4m,4nxk+m1,l+n1Y=i=13j=13x4i,4jwk+i1,l+j1

  令 4q=k+i1,且当i=1时,q=4k,当i=3时,q=2k

  又令 4p=l+j1,且当j=1时,p=4l,当j=3时,p=2l

  则

i=5qkj=5pl

  因此

Y=[yk,l]=i=13j=13x4i,4jwk+i1,l+j1=q=4k2kp=4l2lw4q,4pxk+q1,l+p1

  综上,Y=Y,即 $\text{rot180}(W) * X = \text{rot180}(X) * W $,原命题得证。

习题24.10

  解释残差网络为什么能防止梯度消失和梯度爆炸。

解答:

解答思路:

  1. 给出残差网络的基本概念
  2. 描述梯度消失和梯度爆炸的现象
  3. 解释残差网络能防止梯度消失和梯度爆炸的原因

解答步骤:

第1步:残差网络的基本概念

  根据书中第24章的本章概要的残差网络的描述:

  残差网络是为了解决深度神经网络训练困难而提出的深度学习方法。假设要学习的真实模型是函数 h(x),也可以写作

h(x)=x+(h(x)x)

  残差网络的想法是用一个神经网络 f(x) 近似残差 h(x)x,用 x+f(x) 近似真实模型 h(x),整个过程以递归的方式进行。

xi=xi1+fi(xi1),i=1,2,,n

  残差网络由很多个残差单元串联连接组成。每一个残差单元相当于一般的前馈网络的两层,每一层由线性变换和非线性变换组成,还有一个残差连接。
  残差单元的输入是向量 x,输出是向量 y 时,整个单元的运算是

f(x)=W2relu(W1x)y=relu(x+f(x))

  残差网络可以展开成多个神经网络模块的集成,有很强的表示和学习能力。

第2步:梯度消失和梯度爆炸的现象

  根据书中第23.2.5节的梯度消失与梯度爆炸:

  深度神经网络学习中有时会出现梯度消失(vanishing gradient)或者梯度爆炸(exploding gradient)现象。使用反向传播算法时,首先通过正向传播计算神经网络各层的输出,然后通过反向传播神经网络各层的误差以及梯度,接着利用梯度下降公式对神经网络各层的参数进行更新。在这个过程中,各层的梯度,特别是前面层的梯度,有时会接近0(梯度消失)或接近无穷(梯度爆炸)。梯度消失会导致参数更新停止,梯度爆炸会导致参数溢出,都会使学习无法有效地进行。 反向传播中,首先计算误差向量:

(23.57)δ(t1)={diag(az(t1))W(t)T}δ(t)

之后计算梯度:

(23.58){W(t)L=δ(t)h(t1)Tb(t)L=δ(t)

造成梯度消失和梯度爆炸的原因有两种:

  1. 每一层的误差向量实际由矩阵的连乘决定,连乘得到的矩阵的元素可能会接近0,也可能会接近无穷,导致梯度的元素也会接近0或接近无穷,而且越是前面的层,这个问题就越严重。
  2. 得到每一层的误差向量之前,每个元素乘以激活函数的导数,如果激活函数的导数过小,也容易引起梯度消失,而且越是前面的层,这个问题就越严重。

  假设 L 表示神经网络的层数,wi,j(l) 表示第 l 层中第 i 个神经元到第 l+1 层中第 j 个神经元的权重,ai(l) 表示第 l 层中第 i 个神经元的激活值,zi(l) 表示第 l 层中第 i 个神经元的加权输入,g(z) 表示激活函数,y 表示网络的输出值,yi 表示输出向量的第 i 个元素。则网络的输出可以表示为:

y=g(z(L))=g(w(L)g(w(L1)g(g(w(1)x))))

其中 x表示输入变量。

  对于一个损失函数 J(y,y^),网络的参数 w 可以通过梯度下降法来更新:

wt+1=wtηJ(y,y^)w

  在反向传播过程中,可以通过链式法则来计算每个神经元的梯度。具体地,对于第 l 层中第 i 个神经元的梯度,可以表示为:

Jzi(l)=j=1m(l+1)Jzj(l+1)zj(l+1)zi(l)

其中 m(l+1) 表示第 l+1 层的神经元数量。然后,可以使用梯度下降法来更新参数。

  因为梯度是从输出层向输入层反向传播的,则梯度的大小可以表示为:

|Jzi(l)|=|j=1m(l+1)Jzj(l+1)zj(l+1)zi(l)|.

  由于 zj(l+1) 依赖于 zi(l),因此 zj(l+1)zi(l) 可能会接近0或接近无穷,导致梯度爆炸或梯度消失的情况。

  如果 $\displaystyle \left| \frac{\partial z_j^{(l+1)}}{\partial z_i^{(l)}} \right| > 1 $,那么在反向传播时,梯度会呈现指数级增长,导致梯度爆炸的问题。这种情况通常会导致权重的值变得非常大,从而使模型无法收敛。

  相反,如果 |zj(l+1)zi(l)|<1,那么在反向传播时梯度会逐渐变小,导致梯度消失的问题。这种情况通常会导致网络无法学习到深层特征,从而导致模型性能下降。

第3步:解释残差网络能防止梯度消失和梯度爆炸的原因

  在残差网络中,每个残差单元可以表示为 y=f(x)+x,其中 x 表示输入,f(x) 表示卷积层的输出,y 表示残差单元的输出。从数学的角度来看,这个残差单元可以被看作是一个恒等映射加上一个残差映射,即 y=x+Δ(x),其中 Δ(x)=f(x)x 表示残差。

  简单地,考虑这个残差单元的导数。计算 yx 的导数有:

yx=yf(x)f(x)x+yx=f(x)x+1

  残差网络能防止梯度消失和梯度爆炸的原因如下:

  1. 由于残差网络中的 f(x)x不可能一直为-1,因此在残差网络中不容易出现梯度消失的问题。

  2. 由于残差网络中的残差映射是通过将输入直接加到输出上实现的,因此它不会影响导数的大小。这意味着如果 yx 接近于 1,那么 JxJ 表示损失函数)的值也会比较稳定,不会出现梯度消失或梯度爆炸的问题。

  3. 由于残差映射中的 Δ(x) 只包含了局部信息,而没有涉及到全局信息,因此它通常不会影响梯度的大小。这意味着即使 yx 很小,梯度也可以通过残差映射传递到后面的层中,从而避免了梯度消失的问题。

参考文献

【1】Yoon Kim. 2014. Convolutional Neural Networks for Sentence Classification[J]. cs.CL, abs/1408.5882