偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

機(jī)器學(xué)習(xí)|深度學(xué)習(xí)卷積模型

發(fā)布于 2025-5-27 06:53
瀏覽
0收藏

在早期的圖像分類中,通常流程是先人工提取特征,然后用對(duì)應(yīng)的機(jī)器學(xué)習(xí)算法對(duì)特征進(jìn)行分類,分類的準(zhǔn)確率一般依賴特征選取的方法,甚至依賴經(jīng)驗(yàn)主義。
Yann LeCun最早提出將卷積神經(jīng)網(wǎng)絡(luò)應(yīng)用到圖像識(shí)別領(lǐng)域的,其主要邏輯是使用卷積神經(jīng)網(wǎng)絡(luò)提取圖像特征,并對(duì)圖像所屬類別進(jìn)行預(yù)測(cè),通過(guò)訓(xùn)練數(shù)據(jù)不斷調(diào)整網(wǎng)絡(luò)參數(shù),最終形成一套能自動(dòng)提取圖像特征并對(duì)這些特征進(jìn)行分類的網(wǎng)絡(luò),如圖:

機(jī)器學(xué)習(xí)|深度學(xué)習(xí)卷積模型-AI.x社區(qū)

圖像處理

1、卷積神經(jīng)網(wǎng)絡(luò)

卷積神經(jīng)網(wǎng)絡(luò)(Convolutional Neural Network,CNN)是一種深度學(xué)習(xí)模型,它是一種多層的神經(jīng)網(wǎng)絡(luò),通常由輸入層、卷積層(Convolutional Layer)、池化層(Pooling Layer)和全連接層(Fully Connected Layer)組成。

機(jī)器學(xué)習(xí)|深度學(xué)習(xí)卷積模型-AI.x社區(qū)

卷積神經(jīng)網(wǎng)絡(luò)

  • 卷積層:卷積層是CNN的核心,它通過(guò)卷積運(yùn)算提取圖像的特征,并輸出特征圖,不同的卷積核的目的是提取圖像上的不同的特征,比如邊緣、線條等。
  • 池化層:池化層是對(duì)卷積層輸出的特征圖進(jìn)行降采樣,降低特征圖的維度,同時(shí)保留圖像中重要的信息。
  • 激活函數(shù):激活函數(shù)是對(duì)輸入的數(shù)據(jù)進(jìn)行非線性變換,主要目的是通過(guò)激活函數(shù)的參數(shù)化,使得神經(jīng)網(wǎng)絡(luò)能夠擬合非線性函數(shù)。
  • 全連接層:通過(guò)全連接層將卷積層提取的特征進(jìn)行組合。

2、池化

池化在上一篇《機(jī)器學(xué)習(xí)|深度學(xué)習(xí)基礎(chǔ)知識(shí)》介紹過(guò),主要是降低采樣率,常用的方法有平均池化,最大池化,K-均值池化等,繼續(xù)上一篇代碼做優(yōu)化,通過(guò)??pytorch??的MaxPool2d函數(shù)實(shí)現(xiàn)最大池化:

import torch  
import torch.nn as nn  
import matplotlib.pyplot as plt  
  
# 定義包含池化層的網(wǎng)絡(luò)  
class SimplePoolNet(nn.Module):  
    def __init__(self):  
        super(SimplePoolNet, self).__init__()  
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)  
  
    def forward(self, x):  
        return self.pool(x)  
  
# 初始化網(wǎng)絡(luò)  
net = SimplePoolNet()  
  
# 模擬輸入數(shù)據(jù)  
# 假設(shè)輸入是一個(gè)1x1x4x4的張量(NxCxHxW),其中N是批次大小,C是通道數(shù)  
input_tensor = torch.tensor([[[[1, 2, 3, 4],  
                               [5, 6, 7, 8],  
                               [9, 10, 11, 12],  
                               [13, 14, 15, 16]]]])  
  
# 執(zhí)行池化操作  
output_tensor = net(input_tensor)  
  
# 可視化輸入和輸出  
plt.figure(figsize=(10, 5))  
  
# 顯示輸入  
plt.subplot(1, 2, 1)  
plt.imshow(input_tensor.squeeze(0).squeeze(0), cmap='gray')  
plt.title('Input')  
  
# 顯示輸出  
plt.subplot(1, 2, 2)  
plt.imshow(output_tensor.squeeze(0).squeeze(0), cmap='gray')  
plt.title('Output')  
  
plt.show()

機(jī)器學(xué)習(xí)|深度學(xué)習(xí)卷積模型-AI.x社區(qū)

池化

從上面生成的Output可以看出,池化有如下有點(diǎn):

  • 降低特征圖維度,減少計(jì)算量
  • 對(duì)微小的變化具有魯棒性

3、卷積

3.1 為什么需要卷積?

為什么需要卷積?在全連接網(wǎng)絡(luò)中,輸入層是100X100的矩陣(可以是圖像,也可以是其他特性信息),會(huì)被變換為10000X1的向量,這樣會(huì)存在幾個(gè)問(wèn)題?

  • 輸入的數(shù)據(jù)會(huì)由于變換為1維數(shù)據(jù),導(dǎo)致空間信息丟失,比如矩陣(1,1)和(2,1)位置本來(lái)是相連的,但是展開后變成(1,1)和(100,1),這樣相鄰的相關(guān)性就不存在了;
  • 輸入數(shù)據(jù)維度過(guò)多,會(huì)導(dǎo)致模型參數(shù)等比例增長(zhǎng),容易發(fā)生過(guò)擬合;

為了解決這些問(wèn)題,所以卷積計(jì)算就出現(xiàn)了,具體怎么做的呢?

import torch  
import torch.nn as nn  
  
# 隨機(jī)生成一個(gè)10x10x1的矩陣(假設(shè)是單通道圖像)  
input_tensor = torch.rand(1, 1, 10, 10)  # (batch_size, channels, height, width)  
  
# 定義一個(gè)3x3的卷積層,padding=1以確保輸出尺寸與輸入相同  
conv_layer = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3, padding=1)  
  
# 初始化卷積層的權(quán)重(這里PyTorch會(huì)自動(dòng)處理)   
print("Initial weights of the convolution layer:")  
print(conv_layer.weight)  
  
# 進(jìn)行卷積計(jì)算  
output_tensor = conv_layer(input_tensor)  
  
# 打印輸出張量的尺寸  
print("Output tensor shape:", output_tensor.shape)  
  
# 如果需要,可以打印輸出張量的具體內(nèi)容  
print(output_tensor)

為了方便理解,我從(https://poloclub.github.io/cnn-explainer/)找到動(dòng)態(tài)圖如下:

圖片卷積計(jì)算過(guò)程

3.2 卷積計(jì)算

上一節(jié)說(shuō)了為什么要有卷積,知道卷積就是類似濾波器做矩陣運(yùn)算,其中具體過(guò)程如下:

機(jī)器學(xué)習(xí)|深度學(xué)習(xí)卷積模型-AI.x社區(qū)

卷積計(jì)算

卷積核:卷積核是卷積運(yùn)算的參數(shù),它是一個(gè)矩陣,其數(shù)值對(duì)圖像中與卷積核同樣大小的子塊像素點(diǎn)進(jìn)行卷積計(jì)算時(shí)所采用的權(quán)重;
權(quán)重系數(shù):權(quán)重系數(shù)就是卷積核的參數(shù),捕獲圖像中某像素點(diǎn)及其鄰域像素點(diǎn)所構(gòu)成的特有空間模式;
填充:填充是指在圖像邊緣添加像素點(diǎn),使得卷積核可以覆蓋到整個(gè)圖像,避免卷積運(yùn)算時(shí)輸入圖像尺寸變小;
步長(zhǎng):步長(zhǎng)是指卷積核移動(dòng)的步數(shù),一般設(shè)置為2或者1,在圖像上表示移動(dòng)多少個(gè)像素點(diǎn),比如步長(zhǎng)為2,圖像為100X100,卷積后的矩陣就是50X50;
感受野:感受野是指卷積核覆蓋的區(qū)域,比如3X3的卷積核,1層卷積感受野為3X3,2層卷積感受野為5X5...,根據(jù)最后一層卷積核與原始圖像的關(guān)聯(lián)關(guān)系;
多維卷積核:多維卷積核是指卷積核的維度大于2,比如3D圖像的卷積核就是3X3X3;

3.3 卷積算子

3.3.1 1X1卷積

1X1卷積,即輸入通道數(shù)與輸出通道數(shù)相同,不去考慮輸入數(shù)據(jù)局部信息之間的關(guān)系,而把關(guān)注點(diǎn)放在不同通道間,比如輸入通道數(shù)為3,輸出通道數(shù)為3,那么就是對(duì)每個(gè)通道做1X1卷積,得到3個(gè)輸出通道。

機(jī)器學(xué)習(xí)|深度學(xué)習(xí)卷積模型-AI.x社區(qū)

1X1卷積

從這里看,2D情況下1X1并沒(méi)有特殊之處,但是高維情況下,1X1就可以實(shí)現(xiàn)降維或者升維的效果,比如將各個(gè)維度相同矩陣通過(guò)1X1卷積,就可以獲得2D矩陣。

3.3.2 3D卷積

3D與2D卷積的區(qū)別是多了一個(gè)維度,輸入由(??,??????????,?????????)變?yōu)???,?????????,??????????,?????????),與之對(duì)應(yīng)的應(yīng)用場(chǎng)景如視頻和醫(yī)療圖像圖片等,其中示意圖和樣例代碼如下:

機(jī)器學(xué)習(xí)|深度學(xué)習(xí)卷積模型-AI.x社區(qū)

3D卷積

import torch
import torch.nn as nn

# 輸入數(shù)據(jù)
# 假設(shè)我們有一個(gè)批量大小為1,具有1個(gè)通道的3D數(shù)據(jù),其尺寸為(3, 3, 3)
input_data = torch.tensor([[
    [
        [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
        [[10, 11, 12], [13, 14, 15], [16, 17, 18]],
        [[19, 20, 21], [22, 23, 24], [25, 26, 27]]
    ]
]], dtype=torch.float32)

# 定義3D卷積層
# 輸入通道數(shù)為1,輸出通道數(shù)為1,卷積核尺寸為(2, 2, 2),步長(zhǎng)為1,填充為0
conv3d_layer = nn.Conv3d(in_channels=1, out_channels=1, kernel_size=2, stride=1, padding=0)

# 初始化卷積核權(quán)重
conv3d_layer.weight.data = torch.tensor([[
    [
        [[1, 2], [3, 4]],
        [[5, 6], [7, 8]]
    ]
]], dtype=torch.float32)

# 初始化偏置
conv3d_layer.bias.data = torch.tensor([0], dtype=torch.float32)

# 計(jì)算3D卷積輸出
output = conv3d_layer(input_data)

# 輸出結(jié)果
print("Output shape:", output.shape)
print("Output data:", output)

3.3.3 轉(zhuǎn)置卷積

什么是轉(zhuǎn)置卷積?
卷積的逆運(yùn)算,用于增加上采樣中間層特征圖的空間維度,與通過(guò)卷積核減少輸入元素的常規(guī)卷積相反,轉(zhuǎn)置卷積通過(guò)卷積核廣播輸入元素,從而產(chǎn)生形狀大于輸入的輸出,其中示意圖和樣例代碼如下:

機(jī)器學(xué)習(xí)|深度學(xué)習(xí)卷積模型-AI.x社區(qū)

轉(zhuǎn)置卷積

def trans_conv(X, K):
    h, w = K.shape
    Y = torch.zeros((X.shape[0] + h - 1, X.shape[1] + w - 1))
    for i in range(X.shape[0]):
        for j in range(X.shape[1]):
            Y[i: i + h, j: j + w] += X[i, j] * K
    return Y

X = torch.tensor([[0.0, 1.0], [2.0, 3.0]])
K = torch.tensor([[0.0, 1.0], [2.0, 3.0]])
tcov = trans_conv(X, K)
print("trans_conv: ", trans_conv)

# 輸出結(jié)果
tensor([[ 0.,  0.,  1.],
        [ 0.,  4.,  6.],
        [ 4., 12.,  9.]])

3.3.4 空洞卷積

空洞卷積顧名思義就補(bǔ)足空洞,通過(guò)類似上采樣的方式填充圖片,比如:

機(jī)器學(xué)習(xí)|深度學(xué)習(xí)卷積模型-AI.x社區(qū)

空洞卷積

  • 通過(guò)空洞卷積可以再同樣尺寸的卷積核獲得更大的感受野,從而捕獲更多的信息;
  • 減少計(jì)算量,因?yàn)榭斩淳矸e可以跳過(guò)部分輸入元素,從而減少計(jì)算量;

3.3.5 分離卷積

卷積神經(jīng)網(wǎng)絡(luò)解決了計(jì)算機(jī)視覺領(lǐng)域大部分問(wèn)題,但是可以看到上面一個(gè)問(wèn)題,就是卷積計(jì)算是通過(guò)矩陣操作,計(jì)算量比較大,如何降低計(jì)算量呢?擴(kuò)展到工業(yè)領(lǐng)域?利用矩陣計(jì)算的特點(diǎn),將矩陣分解為兩個(gè)矩陣相乘,如下圖所示:

機(jī)器學(xué)習(xí)|深度學(xué)習(xí)卷積模型-AI.x社區(qū)

分離卷積

利用矩陣原理是拆分兩個(gè)向量的外積:

機(jī)器學(xué)習(xí)|深度學(xué)習(xí)卷積模型-AI.x社區(qū)

卷積外積

這樣可以看出計(jì)算量對(duì)比:原始的計(jì)算量為9次,而拆分計(jì)算量為3次+3次,比原始的計(jì)算量少了3次,所以對(duì)于更大的矩陣計(jì)算量將大大減少。

4、LeNet卷積神經(jīng)網(wǎng)絡(luò)

前面已經(jīng)介紹卷積模型,那么看看最早的卷積神經(jīng)網(wǎng)絡(luò)是如何設(shè)計(jì),總體看來(lái),由兩部分組成:

  • 卷積編碼器:兩個(gè)卷積層組合,主要是對(duì)特征進(jìn)行提??;
  • 全連接層:三個(gè)全連接層組合,主要是對(duì)特征進(jìn)行分類;

機(jī)器學(xué)習(xí)|深度學(xué)習(xí)卷積模型-AI.x社區(qū)

LeNet架構(gòu)圖

代碼可以參考:https://zh.d2l.ai/chapter_convolutional-neural-networks/lenet.html,這里為了方便測(cè)試,我把代碼貼一下:

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

# LeNet-5 
net = nn.Sequential(
    nn.Conv2d(1, 6, kernel_size=5, padding=2), nn.Sigmoid(),
    nn.AvgPool2d(kernel_size=2, stride=2),
    nn.Conv2d(6, 16, kernel_size=5), nn.Sigmoid(),
    nn.AvgPool2d(kernel_size=2, stride=2),
    nn.Flatten(),
    nn.Linear(16 * 5 * 5, 120), nn.Sigmoid(),
    nn.Linear(120, 84), nn.Sigmoid(),
    nn.Linear(84, 10))

X = torch.rand(size=(1, 1, 28, 28), dtype=torch.float32)
for layer in net:
    X = layer(X)
    print(layer.__class__.__name__,'output shape: \t',X.shape)

batch_size = 256
# 下載Fashion-MNIST數(shù)據(jù)集
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size=batch_size)

# 計(jì)算數(shù)據(jù)集上的精度
def evaluate_accuracy_gpu(net, data_iter, device=None):
    if isinstance(net, nn.Module):
        net.eval()  # 設(shè)置為評(píng)估模式
        if not device:
            device = next(iter(net.parameters())).device

    metric = d2l.Accumulator(2)
    with torch.no_grad():
        for X, y in data_iter:
            if isinstance(X, list):
                X = [x.to(device) for x in X]
            else:
                X = X.to(device)
            y = y.to(device)
            metric.add(d2l.accuracy(net(X), y), y.numel())
    return metric[0] / metric[1]

# 訓(xùn)練letnet
def train_letnet(net, train_iter, test_iter, num_epochs, lr, device):
    def init_weights(m):
        if type(m) == nn.Linear or type(m) == nn.Conv2d:
            nn.init.xavier_uniform_(m.weight)
    net.apply(init_weights)
    print('training on', device)
    net.to(device)
    optimizer = torch.optim.SGD(net.parameters(), lr=lr)
    loss = nn.CrossEntropyLoss()
    animator = d2l.Animator(xlabel='epoch', xlim=[1, num_epochs],
                            legend=['train loss', 'train acc', 'test acc'])
    timer, num_batches = d2l.Timer(), len(train_iter)
    for epoch in range(num_epochs):
        # 訓(xùn)練損失之和,訓(xùn)練準(zhǔn)確率之和,樣本數(shù)
        metric = d2l.Accumulator(3)
        net.train()
        for i, (X, y) in enumerate(train_iter):
            timer.start()
            optimizer.zero_grad()
            X, y = X.to(device), y.to(device)
            y_hat = net(X)
            l = loss(y_hat, y)
            l.backward()
            optimizer.step()
            with torch.no_grad():
                metric.add(l * X.shape[0], d2l.accuracy(y_hat, y), X.shape[0])
            timer.stop()
            train_l = metric[0] / metric[2]
            train_acc = metric[1] / metric[2]
            if (i + 1) % (num_batches // 5) == 0 or i == num_batches - 1:
                animator.add(epoch + (i + 1) / num_batches,
                             (train_l, train_acc, None))
        test_acc = evaluate_accuracy_gpu(net, test_iter)
        animator.add(epoch + 1, (None, None, test_acc))
    print(f'loss {train_l:.3f}, train acc {train_acc:.3f}, '
          f'test acc {test_acc:.3f}')
    print(f'{metric[2] * num_epochs / timer.sum():.1f} examples/sec '
          f'on {str(device)}')
    
lr, num_epochs = 0.9, 10
train_letnet(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())

# 輸出結(jié)果(運(yùn)行在CPU上)
Conv2d output shape:     torch.Size([1, 6, 28, 28])
Sigmoid output shape:    torch.Size([1, 6, 28, 28])
AvgPool2d output shape:          torch.Size([1, 6, 14, 14])
Conv2d output shape:     torch.Size([1, 16, 10, 10])
Sigmoid output shape:    torch.Size([1, 16, 10, 10])
AvgPool2d output shape:          torch.Size([1, 16, 5, 5])
Flatten output shape:    torch.Size([1, 400])
Linear output shape:     torch.Size([1, 120])
Sigmoid output shape:    torch.Size([1, 120])
Linear output shape:     torch.Size([1, 84])
Sigmoid output shape:    torch.Size([1, 84])
Linear output shape:     torch.Size([1, 10])
...
loss 0.465, train acc 0.825, test acc 0.783
6611.0 examples/sec on cpu

參考

(1)https://paddlepedia.readthedocs.io/en/latest/tutorials/CNN/convolution_operator/Deformable_Convolution.html
(2)https://zh.d2l.ai/chapter_convolutional-neural-networks/lenet.html

本文轉(zhuǎn)載自????周末程序猿??,作者:周末程序猿

收藏
回復(fù)
舉報(bào)
回復(fù)
相關(guān)推薦