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è)輸出層,我們所說的幾層神經(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ò)的下一層。否則,沒有數(shù)據(jù)被傳遞到網(wǎng)絡(luò)的下一層。關(guān)于節(jié)點(diǎn)激活的過程有沒有覺得非常相似?沒錯(cuò),這其實(shí)就是生物的神經(jīng)元產(chǎn)生神經(jīng)沖動(dòng)的過程的模擬。
神經(jīng)網(wǎng)絡(luò)類型多樣,適用于不同的應(yīng)用場景。例如,循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)通常用于自然語言處理和語音識(shí)別,而卷積神經(jīng)網(wǎng)絡(luò)(ConvNets或CNN)則常用于分類和計(jì)算機(jī)視覺任務(wù)。
在CNN產(chǎn)生之前,識(shí)別圖像中的對(duì)象需要手動(dòng)的特征提取方法。現(xiàn)在,卷積神經(jīng)網(wǎng)絡(luò)為圖像分類和對(duì)象識(shí)別任務(wù)提供了一種更具可擴(kuò)展性的方法,它利用線性代數(shù)的原理,特別是矩陣乘法,來識(shí)別圖像中的模式。
但是,CNN的計(jì)算要求很高,通常需要圖形處理單元 (GPU) 來訓(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í)別圖像越大的部分,較早的層專注于簡單的特征,例如顏色和邊緣。
隨著圖像數(shù)據(jù)在CNN的各層中前進(jìn),它開始識(shí)別物體的較大元素或形狀,直到最終識(shí)別出預(yù)期的物體。
下面將簡單介紹這幾種基本組件的相關(guān)原理和作用。
卷積層
卷積層是CNN的核心組件,其作用是提取樣本的特征。它由三個(gè)部分組成,即輸入數(shù)據(jù)、過濾器和特征圖。在計(jì)算機(jī)內(nèi)部,圖像以像素矩陣的形式存儲(chǔ)。若輸入數(shù)據(jù)是一個(gè)RGB圖像,則由 3D 像素矩陣組成,這意味著輸入將具有三個(gè)維度——高度、寬度和深度。
過濾器,也叫卷積核、特征檢測器,其本質(zhì)是一個(gè)二維(2-D)權(quán)重矩陣,它將在圖像的感受野中移動(dòng),檢查特征是否存在。
卷積核的大小不一,但通常是一個(gè) 3x3 的矩陣,這也決定了感受野的大小。不同卷積核提取的圖像特征也不同。
從輸入圖像的像素矩陣的左上角開始,卷積核的權(quán)重矩陣與像素矩陣的對(duì)應(yīng)區(qū)域進(jìn)行點(diǎn)積運(yùn)算,然后移動(dòng)卷積核,重復(fù)該過程,直到卷積核掃過整個(gè)圖像。這個(gè)過程就叫做卷積。卷積運(yùn)算的最終輸出就稱為特征圖、激活圖或卷積特征。
如上圖所示,特征圖中的每個(gè)輸出值不必連接到輸入圖像中的每個(gè)像素值,它只需要連接到應(yīng)用過濾器的感受野。由于輸出數(shù)組不需要直接映射到每個(gè)輸入值,卷積層(以及池化層)通常被稱為“部分連接”層。
這種特性也被描述為局部連接。當(dāng)卷積核在圖像上移動(dòng)時(shí),其權(quán)重是保持不變的,這被稱為權(quán)值共享。一些參數(shù),如權(quán)重值,是在訓(xùn)練過程中通過反向傳播和梯度下降的過程進(jìn)行調(diào)整的。在開始訓(xùn)練神經(jīng)網(wǎng)絡(luò)之前,需要設(shè)置三個(gè)影響輸出體積大小的超參數(shù):
過濾器的數(shù)量:影響輸出的深度。例如,三個(gè)不同的過濾器將產(chǎn)生三個(gè)不同的特征圖,從而產(chǎn)生三個(gè)深度。
步長(Stride):卷積核在輸入矩陣上移動(dòng)的距離或像素?cái)?shù)。雖然大于等于 2 的步長很少見,但較大的步長會(huì)產(chǎn)生較小的輸出。
零填充(Zero-padding):通常在當(dāng)過濾器不適合輸入圖像時(shí)使用。這會(huì)將輸入矩陣之外的所有元素設(shè)置為零,從而產(chǎn)生更大或相同大小的輸出。有三種類型的填充:
Valid padding:這也稱為無填充。在這種情況下,如果維度不對(duì)齊,則丟棄最后一個(gè)卷積。
Same padding:此填充確保輸出層與輸入層具有相同的大小。
Full padding:這種類型的填充通過在輸入的邊界添加零來增加輸出的大小。
在每次卷積操作之后,CNN的特征圖經(jīng)過激活函數(shù)(Sigmoid、ReLU、Leaky ReLU等)的變換,從而對(duì)輸出做非線性的映射,以提升網(wǎng)絡(luò)的表達(dá)能力。
當(dāng)CNN 有多個(gè)卷積層時(shí),后面的層可以看到前面層的感受野內(nèi)的像素。例如,假設(shè)我們正在嘗試確定圖像是否包含自行車。
我們可以把自行車視為零件的總和,即由車架、車把、車輪、踏板等組成。自行車的每個(gè)單獨(dú)部分在神經(jīng)網(wǎng)絡(luò)中構(gòu)成了一個(gè)較低級(jí)別的模式,各部分的組合則代表了一個(gè)更高級(jí)別的模式,這就在 CNN 中創(chuàng)建了一個(gè)特征層次結(jié)構(gòu)。
池化層
為了減少特征圖的參數(shù)量,提高計(jì)算速度,增大感受野,我們通常在卷積層之后加入池化層(也稱降采樣層)。池化能提高模型的容錯(cuò)能力,因?yàn)樗茉诓粨p失重要信息的前提下進(jìn)行特征降維。
這種降維的過程一方面使得模型更加關(guān)注全局特征而非局部特征,另一方面具有一定的防止過擬合的作用。池化的具體實(shí)現(xiàn)是將感受域中的值經(jīng)過聚合函數(shù)后得到的結(jié)果作為輸出。池化有兩種主要的類型:
最大池化(Max pooling):當(dāng)過濾器在輸入中移動(dòng)時(shí),它會(huì)選擇具有最大值的像素發(fā)送到輸出數(shù)組。與平均池化相比,這種方法的使用頻率更高。
平均池化(Average pooling):當(dāng)過濾器在輸入中移動(dòng)時(shí),它會(huì)計(jì)算感受域內(nèi)的平均值以發(fā)送到輸出數(shù)組。
全連接層
全連接層通常位于網(wǎng)絡(luò)的末端,其結(jié)構(gòu)正如其名。如前所述,輸入圖像的像素值在部分連接層中并不直接連接到輸出層。但是,在全連接層中,輸出層中的每個(gè)節(jié)點(diǎn)都直接連接到前一層中的節(jié)點(diǎn),特征圖在這里被展開成一維向量。
該層根據(jù)通過前幾層提取的特征及其不同的過濾器執(zhí)行分類任務(wù)。雖然卷積層和池化層傾向于使用ReLu函數(shù),但 FC 層通常用Softmax激活函數(shù)對(duì)輸入進(jìn)行適當(dāng)分類,產(chǎn)生[0, 1]之間的概率值。自定義卷積神經(jīng)網(wǎng)絡(luò)進(jìn)行手寫數(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文章
807瀏覽量
59919 -
過濾器
+關(guān)注
關(guān)注
1文章
439瀏覽量
20384 -
卷積神經(jīng)網(wǎng)絡(luò)
+關(guān)注
關(guān)注
4文章
369瀏覽量
12298 -
rnn
+關(guān)注
關(guān)注
0文章
89瀏覽量
7108
原文標(biāo)題:看完這篇我就不信還有人不懂卷積神經(jīng)網(wǎng)絡(luò)!
文章出處:【微信號(hào):vision263com,微信公眾號(hào):新機(jī)器視覺】歡迎添加關(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ò)注意力文本生成變換器編碼器序列表征

評(píng)論