Aprendizaje automático. Redes neuronales (Parte 3) - Red convolucional bajo el microscopio. Explorando la API de Tensorflow.js

Ver también:

  1. Aprendizaje automático. Redes neuronales (parte 1): el proceso de aprendizaje del perceptrón

  2. Aprendizaje automático. Redes neuronales (parte 2): modelado de OR, XOR con TensorFlow.js

En artículos anteriores, solo se utilizó uno de los tipos de capas de redes neuronales: densa, completamente conectada, cuando cada neurona de la capa original tiene una conexión con todas las neuronas de las capas anteriores.

Para manejar una imagen en blanco y negro de 24x24, por ejemplo, tendríamos que convertir la representación matricial de la imagen en un vector que contenga 24x24 = 576 elementos. Como puede imaginar, con tal transformación perdemos un atributo importante: la posición relativa de los píxeles en las direcciones vertical y horizontal de los ejes, y también, probablemente, en la mayoría de los casos, el píxel ubicado en la esquina superior izquierda de la imagen apenas tiene un efecto lógicamente explicable en el píxel esquina inferior derecha.

Para eliminar estas deficiencias, se utilizan capas convolucionales (CNN) para el procesamiento de imágenes.

El propósito principal de CNN es extraer pequeñas partes de la imagen original que contienen rasgos (rasgos) de apoyo (característicos), como bordes, contornos, arcos o caras. En los siguientes niveles de procesamiento, se pueden reconocer fragmentos de texturas repetibles más complejos (círculos, formas cuadradas, etc.) de estos bordes, que luego se pueden plegar en texturas aún más complejas (parte de la cara, rueda de automóvil, etc.).

Por ejemplo, considere un problema clásico: el reconocimiento de imágenes de números. Cada número tiene su propio conjunto de figuras típicas para ellos (círculos, líneas). Al mismo tiempo, cada círculo o línea puede estar compuesto por bordes más pequeños (Figura 1)

Figura 1 - El principio de funcionamiento de capas convolucionales conectadas secuencialmente, con la asignación de rasgos característicos en cada uno de los niveles.  Cada una de las siguientes capas de un conjunto de capas CNN encadenadas extrae patrones más complejos basados ​​en los previamente identificados.
1 – , . CNN , .

1. (convolutional layer)

CNN ( ), c () , .   – CNN – .

, 2x2 ( K) , 2x2 ( N), :

\ left [\ begin {matrix} n_ {11} & n_ {12} \\ n_ {21} & n_ {22} \\\ end {matrix} \ right] \ ast \ left [\ begin {matrix} k_ {11} & k_ {12} \\ k_ {21} & k_ {22} \\\ end {matrix} \ right] = n_ {11} k_ {11} + n_ {12} k_ {12} + n_ {21} k_ {21 } + n_ {22} k_ {22}

  , .

, (fully-connected, dense layers):

{suma = \ \ vec {X}} ^ T \ vec {W} = \ sum_ {i = 1} ^ {n = 4} {x_iw_i} = x_1w_1 + x_2w_2 + x_3w_3 + x_4w_4

, - , – - , ( ).

2. , , , .

Figura 2 - Computación dentro de capas convolucionales
2 –

(kernel size) – 3, 5, 7.

(kernel) [kh, kw], [nh, nw], ( 3):

c_w = n_w-k_w + 1;  c_h = n_h-k_h + 1
 3 –          [3,3]
3 – [3,3]

, . , . , .

, – (padding). , . , ph pw , :

c_w=n_w+p_w-k_w+1; c_h=n_h+p_h-k_h+1

, , , :

p_w=k_w-1; p_h=k_h-1
 4 –
4 –

- . , (stride). – (stride).

 5 –      (stride)
5 – (stride)

, sw, sh, :

c_w=\left \lfloor  (n_w+p_w-k_w+s_w)/s_w \right \rfloor; c_h=\left \lfloor  (n_h+p_h-k_h+s_h)/s_h \right \rfloor

, ( – ). (). , (CONV1) 9x9x1 ( – - ), 2 1x1 (stride) (padding) , , . 9x9x2 2 – (. 6). CONV2 , , 2x2, , 2, 2x2x2. (CONV2) 9x9x4, 4 – .

 6 –
6 –

, kw kh , nw x nh x nd, nd - , , kw x kh x nd ( 6, CONV2).

7 , RGB, 3x3. , (3 ), 3x3x3.

 7 -    ,       RGB
7 - , RGB

TensorFlow.js

, : tf.layers.conv2d, – , :

- filternumber

- kernelSize number | number[] – , number, , –

- strides number | number[] - , [1,1], .

- padding‘same’, ‘valid’ – , ‘valid’

 

.

'same'

, , () (stride) . , - 11 , – 5, 13/5=2.6, – 3 ( 8).

 8 –   ‘valid’  ‘same’      kernelSize=6  strides=5.
8 – ‘valid’ ‘same’ kernelSize=6 strides=5.

stride=1, ( 9), , ( 8).

 9 –   ‘valid’  ‘same’      kernelSize=3  strides=1
9 – ‘valid’ ‘same’ kernelSize=3 strides=1

'valid'

, strides , 8.

TensorFlow.js

, . :

- :

\ left [\ begin {matrix} 1 & 0 & -1 \\ 1 & 0 & -1 \\ 1 & 0 & -1 \\\ end {matrix} \ right]

- :

\ left [\ begin {matrix} 1 & 1 & 1 \\ 0 & 0 & 0 \\ - 1 & -1 & -1 \\\ end {matrix} \ right]

, , tf.browser.fromPixels. , img canvas .

<img src="./sources/itechart.png" alt="Init image" id="target-image"/>
<canvas id="output-image-01"></canvas>

<script>
   const imgSource = document.getElementById('target-image');
   const image = tf.browser.fromPixels(imgSource, 1);
</script>

, , , 3x3, “same” ‘relu’:

const model = tf.sequential({
    layers: [
        tf.layers.conv2d({
            inputShape: image.shape,
            filters: 1,
            kernelSize: 3,
            padding: 'same',
            activation: 'relu'
        })
    ]
});

[NUM_SAMPLES, WIDTH, HEIGHT,CHANNEL], tf.browser.fromPixel [WIDTH, HEIGHT, CHANNEL], – ( , ):

const input = image.reshape([1].concat(image.shape));

. , setWeights Layer, :

model.getLayer(null, 0).setWeights([
    tf.tensor([
         1,  1,  1,
         0,  0,  0,
        -1, -1, -1
    ], [3, 3, 1, 1]),
    tf.tensor([0])
]);

, , 0-255, NUM_SAMPLES:

const output = model.predict(input);

const max = output.max().arraySync();
const min = output.min().arraySync();

const outputImage = output.reshape(image.shape)
    .sub(min)
    .div(max - min)
    .mul(255)
    .cast('int32');

canvas, tf.browser.toPixels:

tf.browser.toPixels(outputImage, document.getElementById('output-image-01'));

:


2. (pooling layer)

, ( ), ,   . , , (pooling layer, subsample layer), . MaxPooling .

, .

. (kernel) , (stride) 1x1, . , (. 10).

Figura 10 - Transformación en la capa de submuestra
10 –

, 4x4, 2x2 (stride) , 2x2, .

, ( 11) . , , MaxPooling . (translation invariance). , , 50%. , , MaxPooling .

Figura 11 - Suavizado de los desplazamientos espaciales después de la capa MaxPooling
11 – MaxPooling

, .

, , – (stride).

MaxPooling AveragePooling, , , . , MaxPooling. AveragePooling , , MaxPooling .

TensorFlow.js (pooling layer)

tf.layers.maxPooling2d tf.layers.averagePooling2d. – , :

- poolSize - número | número [] - la dimensión del filtro, si se especifica el número, entonces la dimensión del filtro toma una forma cuadrada, si se especifica como una matriz, entonces la altura y el ancho pueden diferir

- zancadas - número | number [] es un paso hacia adelante, un parámetro opcional y por defecto tiene la misma dimensión que el poolSize especificado.

- padding - 'igual', 'válido' - establecer relleno de cero, por defecto 'válido'




All Articles