Implementieren Sie die Faltungsfunktion Python manuell


Vorwort

Überprüfen Sie zunächst die Grundlagen von CNN:

„Die von Objekten gesehene Szene ist nicht das ursprüngliche Erscheinungsbild der Welt, sondern eine über lange Zeit gewachsene und für das eigene Lebensumfeld geeignete Wahrnehmungsmethode. Bilderkennung ist eigentlich das Finden (Lernen) menschlicher visueller Assoziationen und wenden Sie sie erneut an."

In einem Computer werden Bilder als Zahlen von 0-255 gespeichert, wobei 0 die dunkelste und 255 die hellste ist. Farbbilder haben drei Kanäle, RGB (rot, grün, blau), und die drei Primärfarben werden zu verschiedenfarbigen Bildern überlagert und im Computer durch dreidimensionale Würfel dargestellt.

Merkmale von CNN:

1) Positionsinvarianz : Egal wo sich das Objekt in einem Bild befindet, es ist dasselbe Objekt, und das Faltungsnetzwerk ist dazu invariant. Warum kann es nicht mit einem Feed-Forward-Netzwerk implementiert werden? Das Feed-Forward-Netzwerk zieht zuerst die dreidimensionalen Daten in ein eindimensionales Eingabenetzwerk und gibt den Endknoten durch eine Reihe von verborgenen Schichten aus. Diese eindimensionalen Daten entsprechen unterschiedlichen Gewichtungen in jedem Netzwerkknoten Objekte geändert werden, muss das Ergebnis anders sein. Aber CNN hat die Eigenschaft der Gewichtsteilung, verschiedene Positionen haben das gleiche Gewicht, also hat die Ausgabe Positionsinvarianz.
2) Lokale Verbindung : Wählen Sie einen lokalen Bereich (Faltungskernfilter) aus, um den dreidimensionalen Tensor zu scannen, und alle Knoten in dem gescannten lokalen Bereich werden gemeinsam mit dem nächsten Punkt verbunden.
Diese Operation kann die Anzahl der Parameter reduzieren, da es nicht notwendig ist, einem Knoten ein Gewicht zuzuweisen, sondern nur lokal ein Gewicht zuzuweisen.
3) Space Sharing : Im Gegensatz zu vollständigen Verbindungen sind die Ausgangsknoten jeder CNN-Schicht nicht mit allen Eingängen verbunden, sondern teilweise verbunden, und der Faltungskern schreitet jedes Mal fort.

Faltungsberechnung :

1) Das Gewicht der Richtung des Kanals C wird nicht geteilt : Das Farbbild ist dreidimensional, die Länge und Breite des Bildes sind lokal verbunden und die Kanalrichtung ist vollständig verbunden. Während des 2D-Faltungsprozesses ist der W H C-Tensor auf einen Punkt auf der Ebene abgebildet , hier Beachten Sie, dass die Gewichte in Richtung Kanal C nicht geteilt werden und die Gewichte auf Gruppe C ausgedehnt werden.
2) Ergänzungsoperation 0 : Um die Randinformationen des Bildes zu erhalten, wird gleichzeitig verhindert, dass das Bild immer kleiner wird. Warum wählen Sie gleichzeitig oft 3 3- und 5 5-Faltungskerne? Das Hinzufügen von 1 Null zum Faltungskern erzeugt die gleiche Größe wie die ursprüngliche Merkmalskarte, und das Hinzufügen von 2 Nullen zum Faltungskern erzeugt die gleiche Größe wie die ursprüngliche Merkmalskarte.

Größenberechnungsformel : (input_size + 2*padding - kernel_size)/stride + 1
* Gewichtsberechnungsformel: kernel_size * kernel_size * kernel_numbers C (c ist die Anzahl der Kanäle)

3) Überlagerung mehrerer Faltungskerne : Verwenden Sie bestimmte Faltungskerne, um bestimmte Existenzen zu erfassen, zum Beispiel: Verwenden Sie verschiedene Kernel, um verschiedene Feature_Maps zu extrahieren, und stapeln Sie sie schließlich, um einen dreidimensionalen Tensor zu bilden, und geben Sie ihn dann in das nächste Inside ein die Faltungsoperation.
4) Nichtlineare Abbildung : Wie beim Feedforward-Netzwerk erhöht das Hinzufügen einer nichtlinearen Transformation die Netzwerkanpassungsfähigkeit.
5) Pooling : Downsampling, weil die identifizierten Feature-Maps redundant sind. Maxpooling: Nimm den Maximalwert eines Faltungskernbereichs und behalte die Texturmerkmale bei Average Pooling: Nimm den Durchschnittswert eines Faltungskernbereichs und behalte den Durchschnittswert Global Pooling: Nimm den Durchschnitt jedes Kanals, der oft stattdessen verwendet wird der vollständigen Verbindung, um eine Überanpassung aufgrund zu vieler Parameter zu verhindern.

Fassen Sie die Implementierungsmethode der CNN-Invarianz zusammen
: 1. Translationsinvarianz: gemeinsame Nutzung von Raum und Parametern 2. Rotationsinvarianz: eine große Datenmenge 3. Größeninvarianz: Anfangsmodul, das nach der Ausgabe mit Faltungskernen verschiedener Größen verkettet wird.
Residual: Informationsinteraktion zwischen verschiedenen Ebenen.

1. CNN-Zusammensetzung

Zunächst muss die Zusammensetzung geklärt werden:
1) Zero Padding
2) Kernal Convolution Kernel
3) Pooling Pooling
4) Convolution Forward Forward Propagation
5) Convolution Backward Backward Propagation

Zwei-, Dreikanal-CNN-Code-Konstruktion

1. 0 bilden

def zero_pad(X, pad):
    """
    ‘constant’——表示连续填充相同的值,每个轴可以分别指定填充值,constant_values=(x, y)时前面用x填充,后面用y填充,缺省值填充0                X的shape (m, n_H, n_W, n_C)表示(图片数量,高,宽,通道)
    pad --在n_H和n_W的边缘补0个数
    返回X_pad --0之后的shape (m, n_H + 2*pad, n_W + 2*pad, n_C)
    """
    X_pad = np.pad(X,((0,0),(pad,pad),(pad,pad),(0,0)),'constant',constant_values = 0)
    return X_pad

2. Faltung in einem Schritt

def conv_single_step(a_slice_prev, W, b):
    """
    Apply one filter defined by parameters W on a single slice (a_slice_prev) of the output activation of the previous layer.
    Arguments:
    a_slice_prev -- slice of input data of shape (f, f, n_C_prev)
    W -- Weight parameters contained in a window - matrix of shape (f, f, n_C_prev)
    b -- Bias parameters contained in a window - matrix of shape (1, 1, 1)
    Returns:
    Z -- a scalar value, result of convolving the sliding window (W, b) on a slice x of the input data
    """
    s = np.multiply(a_slice_prev,W)
    Z = np.sum(s)
    Z = Z + float(b)         #将b转化为浮点数,将Z转成标量.
    return Z

3. Faltung der Conv_forward-Funktion

def conv_forward(A_prev, W, b, hparameters):
    """
    Implements the forward propagation for a convolution function
    Arguments:
    A_prev -- output activations of the previous layer, numpy array of shape (m, n_H_prev, n_W_prev, n_C_prev)
    W -- Weights, numpy array of shape (f, f, n_C_prev, n_C)
    b -- Biases, numpy array of shape (1, 1, 1, n_C)
    hparameters -- python dictionary containing "stride" and "pad"
    Returns:
    Z -- conv output, numpy array of shape (m, n_H, n_W, n_C)
    cache -- cache of values needed for the conv_backward() function
    """
    # Retrieve dimensions from A_prev's shape
    (m, n_H_prev, n_W_prev, n_C_prev) = A_prev.shape
    # Retrieve dimensions from W's shape
    (f, f, n_C_prev, n_C) = W.shape
    # Retrieve information from "hparameters" 
    stride = hparameters['stride']
    pad = hparameters['pad']
    # Compute the dimensions of the CONV output volume using the formula given above.
    n_H = int((n_H_prev - f +2 * pad)/stride) +1
    n_W = int((n_W_prev - f +2 * pad)/stride) +1
    # Initialize the output volume Z with zeros.
    Z = np.zeros((m , n_H, n_W, n_C))
    # Create A_prev_pad by padding A_prev
    A_prev_pad = zero_pad(A_prev, pad)
    for i in range(m):                               # loop over the batch of training examples
        a_prev_pad = A_prev_pad[i]                              # Select ith training example's padded activation
        for h in range(n_H):                           # loop over vertical axis of the output volume
            for w in range(n_W):                       # loop over horizontal axis of the output volume
                for c in range(n_C):                   # loop over channels (= #filters) of the output volume
                    # Find the corners of the current "slice"
                    vert_start = h*stride
                    vert_end = vert_start + f
                    horiz_start =w*stride
                    horiz_end = horiz_start + f
                    # Use the corners to define the (3D) slice of a_prev_pad (See Hint above the cell). (1 line)
                    a_slice_prev = a_prev_pad[vert_start:vert_end, horiz_start:horiz_end, :]
                    # Convolve the (3D) slice with the correct filter W and bias b, to get back one output neuron. (1 line)
                    Z[i, h, w, c] = conv_single_step(a_slice_prev, W[...,c], b[...,c])
    # Making sure your output shape is correct
    assert(Z.shape == (m, n_H, n_W, n_C))
    # Save information in "cache" for the backprop
    cache = (A_prev, W, b, hparameters)
    return Z, cache


Drei, zweidimensionale CNN-Codekonstruktion

Kerncode

def convolution(k, data):
    n,m = data.shape
    img_new = []
    for i in range(n-2):
        line = []
        for j in range(m-2):
            a = data[i:i+3,j:j+3]
            line.append(np.sum(np.multiply(k, a)))
        img_new.append(line)
    return np.array(img_new)
## 卷积核1:垂直边缘检测
k1 = np.array([
    [1,0,-1],
    [1,0,-1],
    [1,0,-1]
])
##卷积核2:水平边缘检测
k2 = np.array([
    [1,1,1],
    [0,0,0],
    [-1,-1,-1]
])

C++ implementiert zweidimensionale Faltung

//c++, arr为原始图像, filter为卷积和,输出为unsigned char类型;
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main() {
    int M, N;
    int tmparr;
    cin >> M >> N;
    vector<vector<int> > array(N, vector<int>(M, 0));
    for(int i = 0; i < N; ++i) {
        for(int j = 0; j < M; ++j) {
            cin >> tmparr;
            array[i][j] = tmparr;
        }
    }
    cout << "array end" << endl;
    int W, H;
    double tmpfilter;
    cin >> W >> H;
    vector<vector<double> > filter(H, vector<double>(W, 0));
    for(int i = 0; i < H; ++i) {
        for(int j = 0; j < W; ++j) {
            cin >> tmpfilter;
            filter[i][j] = tmpfilter;
        }
    }
    cout << "filter end" << endl;
    //vector<vector<unsigned char> > res(N, vector<unsigned char>(M, 0));
    double tmp;
    int top = -(H-1)/2;
    int left = -(W-1)/2;
    for(int i = 0; i < N; ++i) {
        for(int j = 0; j < M; ++j) {
            tmp = 0;
            int boxtop = i + top;
            int boxleft = j + left;
            for(int k = 0; k < H; ++k) {
                for(int l = 0; l < W; ++l) {
                    int tmpboxtop = boxtop + k;
                    int tmpboxleft = boxleft + l;
                    if (tmpboxtop < 0) tmpboxtop = -tmpboxtop;
                    if (tmpboxtop >= N) tmpboxtop = 2*N - 2 - tmpboxtop;
                    if (tmpboxleft < 0) tmpboxleft = - tmpboxleft;
                    if (tmpboxleft >= M) tmpboxleft = 2*M - 2 - tmpboxleft;
                    //cout << "tmpboxtop = " << tmpboxtop << endl;
                    //cout << "tmpboxleft = " << tmpboxleft << endl;
                    //cout << "k = " << k << endl;
                    //cout << "l = " << l << endl;
                    //cout << "array[tmpboxtop][tmpboxleft] = " << array[tmpboxtop][tmpboxleft] << endl;
                    //cout << "filter[k][l] = " << filter[k][l] << endl;
                    tmp += array[tmpboxtop][tmpboxleft] * filter[k][l];
                }
            }
            //res[i][j] = (unsigned char)tmp;
            cout << tmp << " ";
        }
        cout << endl;
    }
    system("pause");
}

Maxpooling

import numpy as np

def max_pooling(feature_map, size=2, stride=2):
   
    #feature_map (h,w)
    height = feature_map.shape[0]
    width = feature_map.shape[1]
    # 确定最后的输出形状
    out_height = np.uint16((height - size) // stride + 1)
    out_width = np.uint16((width - size) // stride + 1)
    # print "out_shape", (out_height, out_width)

    out_pooling = np.zeros((out_height, out_width), dtype=np.uint8)
    x = y = 0
    for m in np.arange(0, height, stride):
        for n in np.arange(0, width, stride):
            try:
                out_pooling[x][y] = np.max(feature_map[m:m + size, n:n + size])
                y += stride
            # try执行不成功, 说明已经超出,终止循环
            except:
                break
        x += stride
        y = 0
    return out_pooling
    
if __name__ == "__main__":
    input = np.arange(9).reshape((3, 3))
    output = max_pooling(input, 2, 1)
    print(output)

Softmax-Implementierung

import numpy as np
def softmax(a):
    exp_a = np.exp(a)
    sum_exp_a = np.sum(exp_a)
    y = exp_a/sum_exp_a
    return y

Supongo que te gusta

Origin blog.csdn.net/PETERPARKERRR/article/details/121775868
Recomendado
Clasificación