práctica de convolución winograd

Referencia del principio básico de la convolución de Winograd:

El algoritmo de Winograd realiza el principio de convolución

Diagrama del proceso de convolución de Winograd:

Tenga en cuenta que los canales de entrada y salida están ocultos en esta imagen. De hecho, cada dimensión espacial también incluye dimensiones de lote y canal de entrada/salida. 

El formato de datos de entrada es [n, h, w, c], y el formato del documento original [Algoritmos rápidos para redes neuronales convolucionales] después de la transformación de entrada es [ho/2*w0/2, 16, n, ci], que en realidad se usa comúnmente [n, ho/2*w0/2, 16, 1, ci]. ho, wo son las dimensiones de alto y ancho de salida, divididas por 2 porque dos elementos adyacentes comparten una matriz de 4x4.

La transformación de entrada es la dimensión del espacio multiplicada por la matriz de transformación. Dado que cada elemento de la dimensión del espacio en realidad corresponde a un vector bidimensional, en realidad es equivalente a realizar varias operaciones de multiplicación y suma entre los vectores correspondientes a cada elemento de la dimensión del espacio. Como se muestra abajo.

El formato original de peso es [c0, ci, h, w], donde h = w = 3, primero procesado como [h, w, ci, co] y luego transformado en [4*4, ci, co] después transformación de peso.

La entrada y el peso convertidos se multiplican por la matriz de lotes para obtener un formato de datos de [n, ho/2*w0/2, 4*4, 1, co].

Finalmente, realice la transformación de salida para obtener el formato [n, ho/2*w0/2, 2*2, co], es decir, [n, ho, wo, co]

Proceso de cálculo de transformación de entrada, asumiendo que el contenido de la dimensión del espacio 4x4 de la entrada x está marcado como ap (puede usar el cálculo de símbolos de Matlab para obtener la relación de cálculo entre la matriz de resultados de conversión y x):

transforma la fórmula de entrada a salida

filter_trans =
[               a,                                     a/2 + b/2 + c/2,                                     a/2 - b/2 + c/2,               c]
[ a/2 + d/2 + g/2, a/4 + b/4 + c/4 + d/4 + e/4 + f/4 + g/4 + h/4 + i/4, a/4 - b/4 + c/4 + d/4 - e/4 + f/4 + g/4 - h/4 + i/4, c/2 + f/2 + i/2]
[ a/2 - d/2 + g/2, a/4 + b/4 + c/4 - d/4 - e/4 - f/4 + g/4 + h/4 + i/4, a/4 - b/4 + c/4 - d/4 + e/4 - f/4 + g/4 - h/4 + i/4, c/2 - f/2 + i/2]
[               g,                                     g/2 + h/2 + i/2,                                     g/2 - h/2 + i/2,               i]
=
[             a,                                (a + b + c)/2,                               (a - b + c)/2,              c]
[ (a + d + g)/2,   ((a + b + c) + (d + e + f) + (g + h + i))/4, ((a + d + g) + (c + f + i) - (b + e + h))/4,, (c + f + i)/2]
[ (a - d + g)/2,   ((a + b + c) - (d + e + f) + (g + h + i))/4, ((a - d + g) + (c - f + i) - (b - e + h))/4,, (c - f + i)/2]
[             g,                                (g + h + i)/2,                               (g - h + i)/2,              i]


data_trans =
[ a - c - i + k, b + c - j - k, c - b + j - k, b - d - j + l]
[ e - g + i - k, f + g + j + k, g - f - j + k, f - h + j - l]
[ g - e + i - k, j - g - f + k, f - g - j + k, h - f + j - l]
[ e - g - m + o, f + g - n - o, g - f + n - o, f - h - n + p]

out_trans =
[ a + b + c + e + f + g + i + j + k, b - c - d + f - g - h + j - k - l]
[ e + f + g - i - j - k - m - n - o, f - g - h - j + k + l - n + o + p]
=
[ a + b + c + (e + f + g) + (i + j + k), b - c - d + (f - g - h) + (j - k - l)]
[ (e + f + g) - (i + j + k )- m - n - o, (f - g - h) - (j - k - l) - n + o + p]

El motor de razonamiento del lado final, como MNN, generalmente no tiene memoria compartida o tiene solo unas pocas, y la capacidad de intercambio de datos entre hilos es relativamente débil. Por lo general, todo el proceso de cálculo se divide en tres pasos de acuerdo con este proceso en lugar de estar escrito un núcleo completo: transformación de entrada, matmul, transformación de salida. El peso es constante durante la inferencia, y la transformación del peso se puede realizar por adelantado mediante el plegado constante.

Para los datos de NHWC, normalmente cada subproceso lee 4x4 y los datos de entrada con una profundidad de canal de 4 se utilizan para la transformación de entrada.

La forma de la parte de multiplicación de matrices es [n, ho/2*w0/2, 16, 1, ci] * [16, ci, co], y la más interna [1, ci] * [ci, co] puede ser considerado a través de cada Cada subproceso calcula la multiplicación de matriz de tamaño de mosaico 1x1 * 1x4 (el principio es el mismo que el mosaico 4x1 * 1x4 o 8x1 * 1x8 comúnmente utilizado, consulte [en construcción] Análisis de rendimiento teórico CUDA GEMM y optimización del kernel - Zhihu ) . Pero esta matriz multiplicada por la forma es demasiado pequeña, lo que da como resultado una pequeña cantidad de cálculo para cada subproceso, y es necesario crear demasiados subprocesos.

Otro método es que el formato de salida de la transformación de entrada es [n, 16, ho/2*w0/2, ci], y luego hacer la multiplicación de matriz con [16, ci, co] después de la transformación de peso, de modo que el más interno El el tamaño de la multiplicación de la matriz aumenta significativamente a [ho/2*w0/2, ci]*[ci, co], lo que es más propicio para la optimización del rendimiento. El formato de salida de la multiplicación de matrices es [n, 16, ho/2*w0/2, co], y la transformación de salida se convierte en [n, ho/2*w0/2, 2*2, co]. Es equivalente a incluir una operación de transposición en la transformación de entrada y salida.

En comparación con la realización de la convolución a través de im2row+matmul, dado que los marcos de convolución adyacentes tienen datos repetidos, para 3x3 pasos = 1, im2row lee los datos en cada posición una vez y los escribe 9 veces, por lo que im2row escribe de nuevo y matmul La cantidad de datos leídos ha aumentado en 9 veces.

La transformación de entrada de Winograd es equivalente al kernel 4x4, stride = 2, la transformación de entrada vuelve a escribir y matmul lee los datos, y el volumen de datos es 4 veces mayor que la entrada.

Reflexión: en comparación con el formato de entrada NHWC o NCHW, ¿el formato de entrada NCHW4 ayudará a la convolución de Winograd?

El im2row en este artículo es relativo a im2col.im2col expande los datos de entrada cubiertos por un núcleo de convolución en una columna de la matriz como la entrada 1 de la multiplicación de matrices, y la expansión de peso es la entrada 0 de la multiplicación de matrices. E im2row es expandir los datos de entrada cubiertos por el núcleo de convolución en una fila de la matriz como la entrada 0 de la multiplicación de matrices, y la expansión de peso es la entrada 1 de la multiplicación de matrices. El rendimiento de volver a escribir direcciones continuas en el método im2row es mejor, y el motor de inferencia generalmente considera la entrada 1 de la multiplicación de matrices en lugar de la entrada 0 como una constante. Por supuesto, los datos de entrada obtenidos por im2col no son absolutos como la entrada 1 de la multiplicación de matrices después de la expansión. También se pueden usar directamente como entrada de multiplicación de matrices 0 y marcados como trans_a=1, porque la optimización de la multiplicación de matrices generalmente también transpone la entrada 0, que es más propicio para la optimización del rendimiento (a diferencia del viejo "sentido común" que transpone b es mejor).

Otras referencias de artículos:

Optimización de Im2col y winograd de la optimización de convolución de inferencia de MegEngine: se busca programador

Explicación detallada de NCNN winograd (1) bzdww

Supongo que te gusta

Origin blog.csdn.net/u013701860/article/details/128083047
Recomendado
Clasificación