Back to Convolution

Anuncio
Back to Convolution
Clase 16, 1/6/2014
http://fisica.cab.cnea.gov.ar/gpgpu/index.php/en/icnpg/clases
Correlación (o convolución) 1D [g1ej5]
Señal
Filtro
Señal filtrada en n
= Area pintada
Correlación (o convolución) 1D [g1ej5]
Para pensar …
¿ Que significa aplicar este filtro particular ?
Stencils
Correlación (o convolución) 1D [g1ej5]
Simple versión serial...
/* convolucion en la cpu: requiere dos loops … */
void conv_cpu(const FLOAT* input, FLOAT* output, const FLOAT* filter)
{
FLOAT temp;
for(int j=0;j<N;j++){
temp=0.0;
for(int i=0;i<Nh;i++){
temp += filter[i]*input[i+j];
}
output[j] = temp;
}
}
Ojo...
void conv_gpu(const FLOAT* d_input, FLOAT* d_output, const FLOAT* d_filter)
{
¿ Simple versión paralela ?
¿....?
}
Correlación (o convolución) 1D [g1ej5]
Simple versión serial...
/* convolucion en la cpu: requiere dos loops … */
void conv_cpu(const FLOAT* input, FLOAT* output, const FLOAT* filter)
{
FLOAT temp;
for(int j=0;j<N;j++){
temp=0.0;
for(int i=0;i<Nh;i++){
temp += filter[i]*input[i+j];
}
output[j] = temp;
}
}
void conv_gpu(const FLOAT* d_input, FLOAT* d_output, const FLOAT* d_filter)
{
¿ Simple versión paralela ?
¿como reparto los datos entre los threads?
¿como reparto la lectura y la escritura?
¿ que loop paralelizo ?... ¿ ambos ?
}
Convolución
// convolucion usando indexado unidimensional de threads/blocks
// un thread por cada elemento del output (la mas simple!)
// todo en memoria global
// lanzamiento: la grilla se puede elegir independiente de N
__global__ void conv_one_thread_per_output_element_all_global
(const FLOAT* input, FLOAT* output, const FLOAT* filter)
{
int j = blockIdx.x * blockDim.x + threadIdx.x;
FLOAT temp;
while(j<N)
{
temp=0.0;
for(int i=0;i<Nh;i++){
temp += filter[i]*input[i+j];
}
output[j]=temp;
j+=gridDim.x*blockDim.x;
}
}
Como lo haria usando thrust::transform?.
Convolución
// convolucion usando indexado unidimensional de threads/blocks
// un thread por cada elemento del output
// filtro en memoria constante, el resto en global
// lanzamiento: la grilla se puede elegir independiente de N
__constant__ FLOAT d_filtro_constant[Nh];
__global__ void conv_one_thread_per_output_element_filter_in_constant
(const FLOAT* input, FLOAT* output)
{
int j = blockIdx.x * blockDim.x + threadIdx.x;
FLOAT temp;
while(j<N)
{
temp=0.0;
for(int i=0;i<Nh;i++){
temp += d_filtro_constant[i]*input[i+j];
}
output[j]=temp;
j+=gridDim.x*blockDim.x;
}
}
Como lo haria usando thrust::transform?.
Convolución
__constant__ FLOAT d_filtro_constant[Nh];
struct
conv_one_thread_per_output_element_filter_in_constant_functor
{
FLOAT* senial;
conv_one_thread_per_output_element_filter_in_constant_functor
(FLOAT* input)
{
senial=input;
};
__device__
FLOAT operator()(const int j)
{
FLOAT temp;
temp=0.0;
for(int i=0;i<Nh;i++){
temp += d_filtro_constant[i]*senial[i+j];
}
return temp;
}
};
MAIN
// hacerlo con un transform de thrust...
thrust::transform( thrust::cuda::par,
thrust::make_counting_iterator(0),thrust::make_counting_iterator(N),
d_output,
conv_one_thread_per_output_element_filter_in_constant_functor(d_input)
);
Convolucion 1d
Códigos: g1ej5_sol.cu
●
●
●
cp -r /share/apps/codigos/alumnos_icnpg2015/convolucion_experimental .
cd convolucion_experimental
Make; qsub submit.sh #caso
Casos para analizar (cual gana?)
1) Filtro y señal en memoria global
2) Filtro en memoria constante, señal en global
3) Filtro en shared, señal en global
4) Filtro y señal en shared
5) Filtro en constante, señal en shared
6) Filtro en registro y señal en global
7) Usando cufft y teorema de la convolucion
8) Filtro en constante y señal en global, usando thrust
9) TODO: hacerlo con CUSP.
10) Filtro y señal en global, 1 thread por * usando atomics
11) Filtro en constante y señal en global, 1 thread por * usando atomics
Convolucion 1d en CUSP
filtro
filtro
filtro
…...
input
…...
=
output
…...
filtro
El operador es ralo para filtros chicos, pero su matriz es muy redundante!
Operadores lineales en CUSP (matrix free!)
int main(void)
{
// number of grid points in each dimension
const int N = 10;
// create a matrix-free linear operator
stencil A(N);
// allocate storage for solution (x) and right hand side (b)
cusp::array1d<float, cusp::device_memory> x(A.num_rows, 0);
cusp::array1d<float, cusp::device_memory> b(A.num_rows, 1);
// set stopping criteria:
// iteration_limit
= 100
// relative_tolerance = 1e-6
cusp::monitor<float> monitor(b, 100, 1e-5, 0, false);
// solve the linear system A * x = b with the Conjugate Gradient method
cusp::krylov::cg(A, x, b, monitor);
return 0;
}
Operadores lineales en CUSP (matrix free)
class stencil : public cusp::linear_operator<float,cusp::device_memory>
{
public:
typedef cusp::linear_operator<float,cusp::device_memory> super;
int N;
// constructor
stencil(int N) : super(N*N,N*N), N(N) {}
// linear operator y = A*x
template <typename VectorType1,typename VectorType2>
void operator()(const VectorType1& x, VectorType2& y) const
{
// obtain a raw pointer to device memory
const float * x_ptr = thrust::raw_pointer_cast(&x[0]);
float * y_ptr = thrust::raw_pointer_cast(&y[0]);
dim3 dimBlock(16,16);
dim3 dimGrid((N + 15) / 16, (N + 15) / 16);
stencil_kernel<<<dimGrid,dimBlock>>>(N, x_ptr, y_ptr);
}
};
Operadores lineales en CUSP (matrix free!)
●
●
●
●
Códigos: stencil.cu
cp -r /share/apps/codigos/cusplibrary-master/examples/LinearOperator .
cd LinearOperator
nvcc stencil.cu -I /share/apps/codigos/cusplibrary-master/
qsub submit.sh
//
//
//
//
//
//
//
//
//
//
//
//
//
This example shows how to use cusp::linear_operator to solve
a linear system with a user-defined linear operator A. The
linear_operator is a way to interface custom sparse matrix
formats or so-called "matrix-free" methods with the iterative
solvers in Cusp. In this example, we illustrate a matrix-free
implementation of a simple 5-point finite-difference stencil,
[ 0 -1 0 ]
[ -1 4 -1 ]
[ 0 -1 0 ]
using a CUDA kernel. We combine the linear_operator with the
Conjugate Gradient method to solve a 2D Poisson problem.
Descargar