01 什么是神經(jīng)網(wǎng)絡(luò)?
在介紹卷積神經(jīng)網(wǎng)絡(luò)之前,我們先回顧一下神經(jīng)網(wǎng)絡(luò)的基本知識(shí)。就目前而言,神經(jīng)網(wǎng)絡(luò)是深度學(xué)習(xí)算法的核心,我們所熟知的很多深度學(xué)習(xí)算法的背后其實(shí)都是神經(jīng)網(wǎng)絡(luò)。
神經(jīng)網(wǎng)絡(luò)由節(jié)點(diǎn)層組成,通常包含一個(gè)輸入層、一個(gè)或多個(gè)隱藏層和一個(gè)輸出層,我們所說(shuō)的幾層神經(jīng)網(wǎng)絡(luò)通常指的是隱藏層的個(gè)數(shù),因?yàn)檩斎雽雍洼敵鰧油ǔJ枪潭ǖ?。?jié)點(diǎn)之間相互連接并具有相關(guān)的權(quán)重和閾值。
如果節(jié)點(diǎn)的輸出高于指定的閾值,則激活該節(jié)點(diǎn)并將數(shù)據(jù)發(fā)送到網(wǎng)絡(luò)的下一層。否則,沒(méi)有數(shù)據(jù)被傳遞到網(wǎng)絡(luò)的下一層。關(guān)于節(jié)點(diǎn)激活的過(guò)程有沒(méi)有覺(jué)得非常相似?沒(méi)錯(cuò),這其實(shí)就是生物的神經(jīng)元產(chǎn)生神經(jīng)沖動(dòng)的過(guò)程的模擬。

神經(jīng)網(wǎng)絡(luò)類(lèi)型多樣,適用于不同的應(yīng)用場(chǎng)景。例如,循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)通常用于自然語(yǔ)言處理和語(yǔ)音識(shí)別,而卷積神經(jīng)網(wǎng)絡(luò)(ConvNets或CNN)則常用于分類(lèi)和計(jì)算機(jī)視覺(jué)任務(wù)。
在CNN產(chǎn)生之前,識(shí)別圖像中的對(duì)象需要手動(dòng)的特征提取方法?,F(xiàn)在,卷積神經(jīng)網(wǎng)絡(luò)為圖像分類(lèi)和對(duì)象識(shí)別任務(wù)提供了一種更具可擴(kuò)展性的方法,它利用線性代數(shù)的原理,特別是矩陣乘法,來(lái)識(shí)別圖像中的模式。
但是,CNN的計(jì)算要求很高,通常需要圖形處理單元 (GPU) 來(lái)訓(xùn)練模型,否則訓(xùn)練速度很慢。
02
什么是卷積神經(jīng)網(wǎng)絡(luò)
卷積神經(jīng)網(wǎng)絡(luò)是一種基于卷積計(jì)算的前饋神經(jīng)網(wǎng)絡(luò)。與普通的神經(jīng)網(wǎng)絡(luò)相比,它具有局部連接、權(quán)值共享等優(yōu)點(diǎn),使其學(xué)習(xí)的參數(shù)量大幅降低,且網(wǎng)絡(luò)的收斂速度也更快。
同時(shí),卷積運(yùn)算能更好地提取圖像的特征。卷積神經(jīng)網(wǎng)絡(luò)的基本組件有卷積層、池化層和全連接層。卷積層是卷積網(wǎng)絡(luò)的第一層,其后可以跟著其他卷積層或池化層,最后一層是全連接層。越往后的層識(shí)別圖像越大的部分,較早的層專(zhuān)注于簡(jiǎn)單的特征,例如顏色和邊緣。
隨著圖像數(shù)據(jù)在CNN的各層中前進(jìn),它開(kāi)始識(shí)別物體的較大元素或形狀,直到最終識(shí)別出預(yù)期的物體。

下面將簡(jiǎn)單介紹這幾種基本組件的相關(guān)原理和作用。
卷積層
卷積層是CNN的核心組件,其作用是提取樣本的特征。它由三個(gè)部分組成,即輸入數(shù)據(jù)、過(guò)濾器和特征圖。在計(jì)算機(jī)內(nèi)部,圖像以像素矩陣的形式存儲(chǔ)。若輸入數(shù)據(jù)是一個(gè)RGB圖像,則由 3D 像素矩陣組成,這意味著輸入將具有三個(gè)維度——高度、寬度和深度。
過(guò)濾器,也叫卷積核、特征檢測(cè)器,其本質(zhì)是一個(gè)二維(2-D)權(quán)重矩陣,它將在圖像的感受野中移動(dòng),檢查特征是否存在。
卷積核的大小不一,但通常是一個(gè) 3x3 的矩陣,這也決定了感受野的大小。不同卷積核提取的圖像特征也不同。
從輸入圖像的像素矩陣的左上角開(kāi)始,卷積核的權(quán)重矩陣與像素矩陣的對(duì)應(yīng)區(qū)域進(jìn)行點(diǎn)積運(yùn)算,然后移動(dòng)卷積核,重復(fù)該過(guò)程,直到卷積核掃過(guò)整個(gè)圖像。這個(gè)過(guò)程就叫做卷積。卷積運(yùn)算的最終輸出就稱(chēng)為特征圖、激活圖或卷積特征。

如上圖所示,特征圖中的每個(gè)輸出值不必連接到輸入圖像中的每個(gè)像素值,它只需要連接到應(yīng)用過(guò)濾器的感受野。由于輸出數(shù)組不需要直接映射到每個(gè)輸入值,卷積層(以及池化層)通常被稱(chēng)為“部分連接”層。
這種特性也被描述為局部連接。當(dāng)卷積核在圖像上移動(dòng)時(shí),其權(quán)重是保持不變的,這被稱(chēng)為權(quán)值共享。一些參數(shù),如權(quán)重值,是在訓(xùn)練過(guò)程中通過(guò)反向傳播和梯度下降的過(guò)程進(jìn)行調(diào)整的。在開(kāi)始訓(xùn)練神經(jīng)網(wǎng)絡(luò)之前,需要設(shè)置三個(gè)影響輸出體積大小的超參數(shù):
過(guò)濾器的數(shù)量:影響輸出的深度。例如,三個(gè)不同的過(guò)濾器將產(chǎn)生三個(gè)不同的特征圖,從而產(chǎn)生三個(gè)深度。
步長(zhǎng)(Stride):卷積核在輸入矩陣上移動(dòng)的距離或像素?cái)?shù)。雖然大于等于 2 的步長(zhǎng)很少見(jiàn),但較大的步長(zhǎng)會(huì)產(chǎn)生較小的輸出。
零填充(Zero-padding):通常在當(dāng)過(guò)濾器不適合輸入圖像時(shí)使用。這會(huì)將輸入矩陣之外的所有元素設(shè)置為零,從而產(chǎn)生更大或相同大小的輸出。有三種類(lèi)型的填充:
Valid padding:這也稱(chēng)為無(wú)填充。在這種情況下,如果維度不對(duì)齊,則丟棄最后一個(gè)卷積。
Same padding:此填充確保輸出層與輸入層具有相同的大小。
Full padding:這種類(lèi)型的填充通過(guò)在輸入的邊界添加零來(lái)增加輸出的大小。
在每次卷積操作之后,CNN的特征圖經(jīng)過(guò)激活函數(shù)(Sigmoid、ReLU、Leaky ReLU等)的變換,從而對(duì)輸出做非線性的映射,以提升網(wǎng)絡(luò)的表達(dá)能力。

當(dāng)CNN 有多個(gè)卷積層時(shí),后面的層可以看到前面層的感受野內(nèi)的像素。例如,假設(shè)我們正在嘗試確定圖像是否包含自行車(chē)。
我們可以把自行車(chē)視為零件的總和,即由車(chē)架、車(chē)把、車(chē)輪、踏板等組成。自行車(chē)的每個(gè)單獨(dú)部分在神經(jīng)網(wǎng)絡(luò)中構(gòu)成了一個(gè)較低級(jí)別的模式,各部分的組合則代表了一個(gè)更高級(jí)別的模式,這就在 CNN 中創(chuàng)建了一個(gè)特征層次結(jié)構(gòu)。

池化層
為了減少特征圖的參數(shù)量,提高計(jì)算速度,增大感受野,我們通常在卷積層之后加入池化層(也稱(chēng)降采樣層)。池化能提高模型的容錯(cuò)能力,因?yàn)樗茉诓粨p失重要信息的前提下進(jìn)行特征降維。
這種降維的過(guò)程一方面使得模型更加關(guān)注全局特征而非局部特征,另一方面具有一定的防止過(guò)擬合的作用。池化的具體實(shí)現(xiàn)是將感受域中的值經(jīng)過(guò)聚合函數(shù)后得到的結(jié)果作為輸出。池化有兩種主要的類(lèi)型:
最大池化(Max pooling):當(dāng)過(guò)濾器在輸入中移動(dòng)時(shí),它會(huì)選擇具有最大值的像素發(fā)送到輸出數(shù)組。與平均池化相比,這種方法的使用頻率更高。
平均池化(Average pooling):當(dāng)過(guò)濾器在輸入中移動(dòng)時(shí),它會(huì)計(jì)算感受域內(nèi)的平均值以發(fā)送到輸出數(shù)組。

全連接層
全連接層通常位于網(wǎng)絡(luò)的末端,其結(jié)構(gòu)正如其名。如前所述,輸入圖像的像素值在部分連接層中并不直接連接到輸出層。但是,在全連接層中,輸出層中的每個(gè)節(jié)點(diǎn)都直接連接到前一層中的節(jié)點(diǎn),特征圖在這里被展開(kāi)成一維向量。
該層根據(jù)通過(guò)前幾層提取的特征及其不同的過(guò)濾器執(zhí)行分類(lèi)任務(wù)。雖然卷積層和池化層傾向于使用ReLu函數(shù),但 FC 層通常用Softmax激活函數(shù)對(duì)輸入進(jìn)行適當(dāng)分類(lèi),產(chǎn)生[0, 1]之間的概率值。自定義卷積神經(jīng)網(wǎng)絡(luò)進(jìn)行手寫(xiě)數(shù)字識(shí)別
導(dǎo)包
import time import numpy as np import torch import torch.nn.functional as F from torchvision import datasets from torchvision import transforms from torch.utils.data import DataLoader if torch.cuda.is_available(): torch.backends.cudnn.deterministic = True
設(shè)置參數(shù) & 加載數(shù)據(jù)集
##########################
### SETTINGS
##########################
# Device
device = torch.device("cuda:3" if torch.cuda.is_available() else "cpu")
# Hyperparameters
random_seed = 1
learning_rate = 0.05
num_epochs = 10
batch_size = 128
# Architecture
num_classes = 10
##########################
### MNIST DATASET
##########################
# Note transforms.ToTensor() scales input images
# to 0-1 range
train_dataset = datasets.MNIST(root='data',
train=True,
transform=transforms.ToTensor(),
download=True)
test_dataset = datasets.MNIST(root='data',
train=False,
transform=transforms.ToTensor())
train_loader = DataLoader(dataset=train_dataset,
batch_size=batch_size,
shuffle=True)
test_loader = DataLoader(dataset=test_dataset,
batch_size=batch_size,
shuffle=False)
# Checking the dataset
for images, labels in train_loader:
print('Image batch dimensions:', images.shape)
print('Image label dimensions:', labels.shape)
break
模型定義
##########################
### MODEL
##########################
class ConvNet(torch.nn.Module):
def __init__(self, num_classes):
super(ConvNet, self).__init__()
# calculate same padding:
# (w - k + 2*p)/s + 1 = o
# => p = (s(o-1) - w + k)/2
# 28x28x1 => 28x28x8
self.conv_1 = torch.nn.Conv2d(in_channels=1,
out_channels=8,
kernel_size=(3, 3),
stride=(1, 1),
padding=1) # (1(28-1) - 28 + 3) / 2 = 1
# 28x28x8 => 14x14x8
self.pool_1 = torch.nn.MaxPool2d(kernel_size=(2, 2),
stride=(2, 2),
padding=0) # (2(14-1) - 28 + 2) = 0
# 14x14x8 => 14x14x16
self.conv_2 = torch.nn.Conv2d(in_channels=8,
out_channels=16,
kernel_size=(3, 3),
stride=(1, 1),
padding=1) # (1(14-1) - 14 + 3) / 2 = 1
# 14x14x16 => 7x7x16
self.pool_2 = torch.nn.MaxPool2d(kernel_size=(2, 2),
stride=(2, 2),
padding=0) # (2(7-1) - 14 + 2) = 0
self.linear_1 = torch.nn.Linear(7*7*16, num_classes)
for m in self.modules():
if isinstance(m, torch.nn.Conv2d) or isinstance(m, torch.nn.Linear):
m.weight.data.normal_(0.0, 0.01)
m.bias.data.zero_()
if m.bias is not None:
m.bias.detach().zero_()
def forward(self, x):
out = self.conv_1(x)
out = F.relu(out)
out = self.pool_1(out)
out = self.conv_2(out)
out = F.relu(out)
out = self.pool_2(out)
logits = self.linear_1(out.view(-1, 7*7*16))
probas = F.softmax(logits, dim=1)
return logits, probas
torch.manual_seed(random_seed)
model = ConvNet(num_classes=num_classes)
model = model.to(device)
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
模型訓(xùn)練
def compute_accuracy(model, data_loader):
correct_pred, num_examples = 0, 0
for features, targets in data_loader:
features = features.to(device)
targets = targets.to(device)
logits, probas = model(features)
_, predicted_labels = torch.max(probas, 1)
num_examples += targets.size(0)
correct_pred += (predicted_labels == targets).sum()
return correct_pred.float()/num_examples * 100
start_time = time.time()
for epoch in range(num_epochs):
model = model.train()
for batch_idx, (features, targets) in enumerate(train_loader):
features = features.to(device)
targets = targets.to(device)
### FORWARD AND BACK PROP
logits, probas = model(features)
cost = F.cross_entropy(logits, targets)
optimizer.zero_grad()
cost.backward()
### UPDATE MODEL PARAMETERS
optimizer.step()
### LOGGING
if not batch_idx % 50:
print ('Epoch: %03d/%03d | Batch %03d/%03d | Cost: %.4f'
%(epoch+1, num_epochs, batch_idx,
len(train_loader), cost))
model = model.eval()
print('Epoch: %03d/%03d training accuracy: %.2f%%' % (
epoch+1, num_epochs,
compute_accuracy(model, train_loader)))
print('Time elapsed: %.2f min' % ((time.time() - start_time)/60))
print('Total Training Time: %.2f min' % ((time.time() - start_time)/60))
模型評(píng)估
with torch.set_grad_enabled(False): # save memory during inference
print('Test accuracy: %.2f%%' % (compute_accuracy(model, test_loader)))
輸出如下
Test accuracy: 97.97%
審核編輯:劉清
-
RGB
+關(guān)注
關(guān)注
4文章
835瀏覽量
62197 -
過(guò)濾器
+關(guān)注
關(guān)注
1文章
444瀏覽量
21029 -
卷積神經(jīng)網(wǎng)絡(luò)
+關(guān)注
關(guān)注
4文章
374瀏覽量
12909 -
rnn
+關(guān)注
關(guān)注
0文章
92瀏覽量
7373
原文標(biāo)題:看完這篇我就不信還有人不懂卷積神經(jīng)網(wǎng)絡(luò)!
文章出處:【微信號(hào):vision263com,微信公眾號(hào):新機(jī)器視覺(jué)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
什么是卷積神經(jīng)網(wǎng)絡(luò)?卷積神經(jīng)網(wǎng)絡(luò)對(duì)人工智能和機(jī)器學(xué)習(xí)的意義
詳解深度學(xué)習(xí)、神經(jīng)網(wǎng)絡(luò)與卷積神經(jīng)網(wǎng)絡(luò)的應(yīng)用
全連接神經(jīng)網(wǎng)絡(luò)和卷積神經(jīng)網(wǎng)絡(luò)有什么區(qū)別
循環(huán)神經(jīng)網(wǎng)絡(luò)卷積神經(jīng)網(wǎng)絡(luò)注意力文本生成變換器編碼器序列表征
什么是神經(jīng)網(wǎng)絡(luò)?什么是卷積神經(jīng)網(wǎng)絡(luò)?
評(píng)論