"Introducción al aprendizaje profundo" Capítulo 7 Combate real: Reconocimiento de dígitos escritos a mano - Red neuronal convolucional

Sugerencia: después de escribir el artículo, la tabla de contenido se puede generar automáticamente. Cómo generarla puede consultar el documento de ayuda a la derecha


prefacio

Recientemente leí el capítulo 7 del libro "Introducción a la teoría e implementación basadas en Python de aprendizaje profundo", este capítulo explica principalmente las redes neuronales convolucionales. La red neuronal convolucional (CNN) se puede utilizar en varias ocasiones de reconocimiento de imágenes y reconocimiento de voz.


1. Una pequeña introducción

1. Estructura general

En comparación con la red neuronal aprendida anteriormente, CNN tiene una capa convolucional más (capa convolucional) y una capa de agrupación (capa de agrupación).

El orden de conexión de las capas de CNN es "Convolución - ReLU - (agrupación)" (la capa de agrupación a veces se omite). Esto se puede entender porque la conexión anterior "Affine - ReLU" fue reemplazada por una conexión "Convolution - ReLU - (Pooling)".
inserte la descripción de la imagen aquí

2. Capa de convolución

En la capa completamente conectada, los datos se aplanan en datos unidimensionales y se ingresan en la red. Entonces, en la capa completamente conectada, la forma de los datos en realidad se ignora. Pero la capa convolucional puede mantener la forma de los datos sin cambios.

En CNN, los datos de entrada y salida de la capa convolucional a veces se denominan mapa de características . Entre ellos, los datos de entrada de la capa convolucional se denominan mapa de características de entrada (mapa de características de entrada) , y los datos de salida se denominan mapa de características de salida (mapa de características de salida) . En este libro, "datos de entrada-salida" y "mapa de características" se utilizan como palabras sinónimas.

operación de convolución

Los objetos involucrados en la operación de convolución son los datos de entrada y los filtros. (Suponiendo que ahora estamos ingresando datos bidimensionales, el filtro correspondiente también es bidimensional)
inserte la descripción de la imagen aquí
Para los datos de entrada, la operación de convolución desliza la ventana del filtro en un cierto intervalo y lo aplica. La ventana mencionada aquí se refiere a la parte gris de 3 × 3 en la Figura 7-4. Como se muestra en la figura 7-4, el elemento del filtro en cada posición se multiplica por el elemento correspondiente de la entrada y luego se suma (este cálculo a veces se denomina operación de multiplicación y acumulación). Luego, guarde este resultado en la ubicación correspondiente de la salida. Realice este proceso en todas las posiciones para obtener el resultado de la operación de convolución.

En una red neuronal completamente conectada, además de los parámetros de peso, también existen sesgos. En CNN, los parámetros del filtro corresponden a los pesos anteriores. Además, hay parcialidad en CNN. El ejemplo de operación de convolución en la Figura 7-3 se muestra hasta la etapa en la que se aplica el filtro. El flujo de procesamiento de la operación de convolución, incluida la polarización, se muestra en la Figura 7-5.
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

relleno

Antes de que se procese la capa convolucional, a veces es necesario completar datos fijos (como 0, etc.) alrededor de los datos de entrada
, lo que se denomina relleno .

inserte la descripción de la imagen aquí

A través del relleno, los datos de entrada de tamaño (4, 4) se convierten en (6, 6) forma. Luego, se aplica un filtro de tamaño (3, 3), lo que da como resultado datos de salida de tamaño (4, 4).

En este ejemplo, el relleno se establece en 1, pero el valor de relleno también se puede establecer en cualquier número entero, como 2, 3, etc. En el ejemplo de la Figura 7-5, si el relleno se establece en 2, el tamaño de los datos de entrada se convierte en (8, 8); si el relleno se establece en 3, el tamaño se convierte en (10, 10).

El relleno se utiliza principalmente para cambiar el tamaño de la salida.

paso

inserte la descripción de la imagen aquí
Operación de convolución basada en múltiples filtros:
inserte la descripción de la imagen aquí

3. Capa de agrupación

Pooling es una operación que reduce el espacio en las direcciones de altura y longitud. En términos generales, la agrupación se divide en dos tipos: agrupación máxima y agrupación promedio.

Agrupación máxima: obtenga el valor máximo.
Agrupación promedio: obtenga el valor promedio.

El ejemplo de la figura a continuación es la secuencia de procesamiento cuando se realiza la agrupación 2*2 Max de acuerdo con el paso 2.
inserte la descripción de la imagen aquí
Características de la capa de agrupación:
1. No hay parámetros para aprender.
La agrupación solo obtiene el valor máximo o promedio del área objetivo y no hay parámetros que aprender.
2. El número de canales no cambia.
Después de la operación de agrupación, el número de canales de datos de entrada y datos de salida no ha cambiado. Como se muestra en la figura a continuación, los cálculos se realizan de forma independiente por el número de canales.
inserte la descripción de la imagen aquí

2. Implementación de capa convolucional y capa de agrupación

Consulte esta publicación de blog: https://blog.csdn.net/LeungSr/article/details/127203161

3. Todos los códigos y resultados de ejecución

from collections import OrderedDict

import sys, os

sys.path.append(os.pardir)
import numpy as np
import matplotlib.pyplot as plt
from common.functions import *
from common.layers import *
from collections import OrderedDict
from dataset.mnist import load_mnist
from dataset.two_layer_net import TwoLayerNet
from common.trainer import Trainer
import pickle

class SimpleConvNet:
    # input_dim 输入数据的尺寸,默认1通道,高28,长28
    # filter_num 滤波器数量
    # filter_size 滤波器大小
    # pad 填充
    # stride 步幅,默认为1
    # hidden_size 隐藏层(全连接)中的神经元数量
    # output_size 输出层(全连接)中的神经元数量
    # weight_init_std 初始化时权重的标准差
    def __init__(self, input_dim=(1,28,28),
                 conv_param={
    
    'filter_num':30, 'filter_size':5, 'pad':0, 'stride':1},
                 hidden_size=100, output_size=10, weight_init_std=0.01):
        filter_num = conv_param['filter_num']
        filter_size = conv_param['filter_size']
        filter_pad = conv_param['pad']
        filter_stride = conv_param['stride']
        input_size = input_dim[1]
        conv_output_size = (input_size - filter_size + 2*filter_pad) / filter_stride + 1
        pool_output_size = int(filter_num * (conv_output_size/2) * (conv_output_size/2))
        # 初始化权重参数
        self.params = {
    
    }
        self.params['W1'] = weight_init_std * np.random.randn(filter_num, input_dim[0], filter_size, filter_size)
        self.params['b1'] = np.zeros(filter_num)
        self.params['W2'] = weight_init_std * np.random.randn(pool_output_size, hidden_size)
        self.params['b2'] = np.zeros(hidden_size)
        self.params['W3'] = weight_init_std * np.random.randn(hidden_size, output_size)
        self.params['b3'] = np.zeros(output_size)
        # 生成必要的层
        self.layers = OrderedDict()
        self.layers['Conv1'] = Convolution(self.params['W1'], self.params['b1'], conv_param['stride'], conv_param['pad'])
        self.layers['Relu1'] = Relu()
        self.layers['Pool1'] = Pooling(pool_h=2, pool_w=2, stride=2)
        self.layers['Affine1'] = Affine(self.params['W2'], self.params['b2'])
        self.layers['Relu2'] = Relu()
        self.layers['Affine2'] = Affine(self.params['W3'], self.params['b3'])
        self.last_layer = SoftmaxWithLoss()

    def predict(self, x):
        for layer in self.layers.values():
            x = layer.forward(x)
        return x

    # x是输入数据,t是标签
    def loss(self, x, t):
        y = self.predict(x)
        return self.last_layer.forward(y, t)

    # 计算精确度
    def accuracy(self, x, t):
        y = self.predict(x)
        y = np.argmax(y, axis=1)
        if t.ndim != 1:
            t = np.argmax(t, axis=1)
        accuracy = np.sum(y == t) / float(x.shape[0])
        return accuracy

    def save_params(self, file_name="params.pkl"):
        params = {
    
    }
        for key, val in self.params.items():
            params[key] = val
        with open(file_name, 'wb') as f:
            pickle.dump(params, f)

    def load_params(self, file_name="params.pkl"):
        with open(file_name, 'rb') as f:
            params = pickle.load(f)
        for key, val in params.items():
            self.params[key] = val

        for i, key in enumerate(['Conv1', 'Affine1', 'Affine2']):
            self.layers[key].W = self.params['W' + str(i + 1)]
            self.layers[key].b = self.params['b' + str(i + 1)]


    def gradient(self, x, t):
        # forward
        self.loss(x, t)
        # backward
        dout = 1
        dout = self.last_layer.backward(dout)
        layers = list(self.layers.values())
        layers.reverse()
        for layer in layers:
            dout = layer.backward(dout)
        # 设定
        grads = {
    
    }
        grads['W1'] = self.layers['Conv1'].dW
        grads['b1'] = self.layers['Conv1'].db
        grads['W2'] = self.layers['Affine1'].dW
        grads['b2'] = self.layers['Affine1'].db
        grads['W3'] = self.layers['Affine2'].dW
        grads['b3'] = self.layers['Affine2'].db

        return grads


# 读入数据
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=False)

# 处理花费时间较长的情况下减少数据
# x_train, t_train = x_train[:5000], t_train[:5000]
# x_test, t_test = x_test[:1000], t_test[:1000]

max_epochs = 20

network = SimpleConvNet(input_dim=(1, 28, 28),
                        conv_param={
    
    'filter_num': 30, 'filter_size': 5, 'pad': 0, 'stride': 1},
                        hidden_size=100, output_size=10, weight_init_std=0.01)

trainer = Trainer(network, x_train, t_train, x_test, t_test,
                  epochs=max_epochs, mini_batch_size=100,
                  optimizer='Adam', optimizer_param={
    
    'lr': 0.001},
                  evaluate_sample_num_per_epoch=1000)
trainer.train()

# 保存参数
network.save_params("params.pkl")
print("Saved Network Parameters!")

# 绘制图形
markers = {
    
    'train': 'o', 'test': 's'}
x = np.arange(max_epochs)
plt.plot(x, trainer.train_acc_list, marker='o', label='train', markevery=2)
plt.plot(x, trainer.test_acc_list, marker='s', label='test', markevery=2)
plt.xlabel("epochs")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
plt.legend(loc='lower right')
plt.show()






resultado de la operación:
inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/rellvera/article/details/128054009
Recomendado
Clasificación