Experiencias con Python y CUDA en
Computacin de Altas Prestaciones
Sergio Armas, Lionel Mena, Alejandro Samarn,
Vicente Blanco
1
, Alberto Morales y Francisco Almeida
Resumen--- La computacin paralela no ha cesado de
explorar nuevos horizontes con el objetivo de obtener
mejoras tangibles de rendimiento en la ejecucin de
algoritmos de toda clase. Si bien durante muchos aos
se ha seguido el camino de innovar en la arquitectura
de las CPU y crear software que se aproveche de esos
benecios, la consolidacin de la que vienen disfru-
tando en la ltima dcada los dispositivos grcos co-
mo hardware de cmputo general es difcil de ignorar.
Este cambio de paradigma trae consigo nuevas formas
de programar, nuevas herramientas y por supuesto,
nuevos desafos. El hecho de que el lenguaje C y sus
derivados sean la lingua franca de este tipo de pro-
gramacin no debera sorprender a propios ni a ex-
traos, pero otros lenguajes se van haciendo hueco
poco a poco. Es el caso de Python, que gracias al
wrapper PyCUDA [1] es capaz de ofrecer al progra-
mador acceso a la computacin de altas prestaciones
sobre dispositivos grcos sin renunciar a la como-
didad y dinamismo de este lenguaje. El propsito de
este artculo es comprobar las facilidades que promete
PyCUDA as como su rendimiento frente a problemas
reales.
Palabras clave--- Python, CUDA, PyCUDA, Py-
CUBLAS
I. Introduccin
La capacidad de cmputo de las unidades de proce-
samiento grco (GPU) ha alcanzado en los ltimos
aos un desarrollo notable, que ha crecido de ma-
nera paralela a un fuerte incremento en la produc-
cin y demanda de dispositivos que las integran, tales
como smartphones, tablets, etc., adems de seguir
presentes en tarjetas grcas o placas base con cada
vez ms relevancia. Precisamente, dicho aumento de
potencia ha comenzado a hacer atractivo su empleo
para la manipulacin de cantidades masivas de datos
en mbitos ajenos al del video tales como criptologa,
biologa computacional, clculo cientco etc., que,
por su naturaleza paralela, son susceptibles de eje-
cutarse con ms eciencia, incluso, que en una CPU
tradicional. Esta tcnica de usar la GPU en aplica-
ciones que tradicionalmente se haban ejecutado en
CPU recibe el nombre de GPGPU (General-purpose
computing on graphics processing units).
A pesar de que existen diversos fabricantes es-
pecializados en dispositivos grcos que ofrecen al-
gn tipo de framework para desarrollo de aplica-
ciones paralelas sobre GPGPU, e incluso alterna-
tivas ms generales como OpenCL [2], NVIDIA es
probablemente el que ms ha apostado por este en-
foque. Prcticamente desde los albores de esta com-
putacin, ha ido desarrollando un modelo de progra-
macin denominado CUDA (Compute Unied De-
vice Architecture) [3], que permite al programador
1
Dpto. Estadstica, I.O. y Computacin, Univ. La Laguna,
e-mail: vblanco@[Link]
ejecutar algoritmos casi arbitrarios en sus GPU. El
lenguaje de programacin diseado para ello es una
variacin de C que contiene extensiones para traba-
jar con la GPU, amn de ciertas restricciones (no
permite recursividad ni punteros a funciones, solo
permite nmeros en precisin simple en la mayora
de tarjetas lanzadas al mercado hasta ahora, etc.).
El trmino anglosajn wrapper se emplea en com-
putacin para designar, a grandes rasgos, un tipo de
software que aade una capa de cdigo para traducir
de una interfaz existente a otra, generalmente con la
nalidad de ganar portabilidad, sencillez o compati-
bilidad. PyCUDA, que ha sido desarrollado por An-
dreas Klckner
2
, es un ejemplo de esto: ejerce la fun-
cin de interfaz en Python para las funciones nativas
escritas en C que proporciona la SDK de NVIDIA.
La principal ventaja que representa la utilizacin de
PyCUDA en el desarrollo, en contraposicin al uso
de las funciones propias de NVIDIA bajo C/C++, es
sin duda la comodidad. PyCUDA permite abstraer,
por ejemplo, de todo lo relacionado con la reserva
y liberacin de memoria en el dispositivo, lo cual
hubiera representado una carga adicional de trabajo
destacable en la versin C/C++. En este artculo se
analizar si las ventajas de utilizar un lenguaje inter-
pretado de muy alto nivel para ejecutar algoritmos
en una GPU compensa la menor velocidad inherente
a los lenguajes interpretados.
II. Acerca del modelo de programacin
CUDA
El diseo de CUDA tiene como el objetivo el desar-
rollo de software que, de manera transparente, escale
el paralelismo de manera que se pueda aprovechar
el incremento del nmero de procesadores al tiem-
po que mantiene una baja curva de aprendizaje para
los programadores familiarizados con lenguajes es-
tndares como el C. Para lograr esto fundamental-
mente posee tres puntos clave:
Jerarqua de hilos
Jerarqua de memoria
Sincronizaciones por barrera
A. Jerarqua de Hilos
Se dene en base a 3 elementos: hilo, bloque y grid.
As pues, cada grid contiene bloques y estos a su vez
contienen hilos.
Por conveniencia, cada hilo se identica por un
vector de tres componentes (x, y, z) denomina-
2
Courant Institute of Mathematical Sciences - New York
University - [Link]
Fig. 1. Jerarqua de hilos y patrones de acceso
do threadIdx, as los hilos pueden identicados por
un ndice threadIdx unidimensional, bidimensional
o tridimensional, formando a su vez un bloque uni-
dimensional, bidimensional o tridimensional. Esto
provee de una manera natural de realizar clculos
sobre elementos tales como un vector o una matriz.
B. Jerarqua de Memoria
Los hilos en CUDA pueden acceder a distintas
memorias, unas compartidas y otras privadas. En
primer lugar tenemos la memoria local privada de
cada hilo. Cada bloque de hilos posee memoria com-
partida visible solo por los hilos del bloque y con el
mismo tiempo de vida del bloque. Finalmente cada
hilo en cada bloque de cada grid puede acceder a la
memoria global.
Adicionalmente existen dos espacios de memoria
de slo lectura accesible por todos los hilos: la memo-
ria de texturas y la memoria de constante, opti-
mizadas para usos especcos. Las memorias global,
de textura y constante persisten mientras el kernel
permanezca en accin.
Asi como se puede identicar los hilos dentro de
un bloque, se pueden identicar los bloques dentro de
un grid, mediante una variable blockIdx que tambin
puede ser un ndice unidimensional, bidimensional o
tridimensional.
C. Sincronizaciones por Barrera
Como los distintos hilos colaboran entre ellos y
pueden compartir datos, se requieren directivas de
sincronizacin. En CUDA se puede especicar una
sincronizacin del tipo barrera, en la que todos los
hilos esperan a que los dems lleguen al mismo punto.
D. Kernel
CUDA extiende el lenguaje permitiendo denir
funciones llamadas kernels, que cuando son invo-
cadas, son ejecutadas N veces en paralelo por N difer-
ente hilos de CUDA. Estas abstracciones permiten
un granulado no en el paralelismo de los datos y
los hilos, conduciendo al programador a dividir el
problema en subproblemas que pueden ser tratados
independientemente y en paralelo por bloques de hi-
los, y su vez dividir estos subproblemas en elementos
individuales que pueden ser resueltos en paralelo y de
manera cooperativa por todos los hilos de un mismo
bloque.
Esta estructura preserva la expresividad del
lenguaje permitiendo que los hilos cooperen en la
resolucin de cada subproblema, y al mismo tiem-
po permite la escalabilidad. En efecto, cada bloque
de hilos puede ser programado en cualquier ncleo
de procesamiento que este disponible, en cualquier
orden, concurrente o secuencialmente. Por lo que
cualquier programa CUDA ya compilado puede eje-
cutarse en sistemas con distinto nmero de ncleos de
procesamiento, y solo el sistema de tiempo de ejecu-
cin debe conocer el dicho nmero de ncleos fsicos.
Todo esto desde el punto de vista del programador
consiste en la extensin del lenguaje con un conjunto
reducido de instrucciones, lo que supone un curva de
aprendizaje suave; cabe notar, sin embargo, que a pe-
sar de que CUDA permite la programacin de kernels
con pocas restricciones sobre el lenguaje, es necesario
adoptar ciertas pautas a la hora de generar los ker-
nels de las aplicaciones de inters, ya que de no seguir
estas directrices el rendimiento se ver afectado seve-
ramente. Existen varias de ellas, pero las ms impor-
tantes son dos: garantizar la coalescencia en el acceso
a memoria (tanto en operaciones de lectura como de
escritura) y usar la memoria compartida comn a los
hilos de un mismo bloque, para aprovechar su mayor
velocidad de acceso en comparacin con la memoria
global del dispositivo [4]. Si se tienen en cuenta am-
bas caractersticas, es muy probable que el kernel en
cuestin tenga un rendimiento excelente.
III. Computacin con PyCUDA
A. Requerimientos previos
Antes de nada, es conveniente mencionar que
para poder utilizar PyCUDA en una determinada
mquina de pruebas, es necesario proveer primero de
todo un framework asociado que necesita dicho soft-
ware. En lneas generales, PyCUDA necesita obvia-
mente de Python instalado en el sistema, as como
de NumPy/SciPy y de las libreras boost. Estos a su
vez tienen algunas dependencias de software con la
Fig. 2. Software necesario para ejecutar PyCUDA
que se debe tener cuidado, ya que de la correcta con-
guracin de ATLAS y LAPACK, por ejemplo, va
a depender en buena medida el rendimiento poste-
rior de PyCUDA. Asimismo, para el ejemplo prc-
tico del desarrollo de un algoritmo de deteccin de
movimiento, se impone la necesidad de disponer de
algunas libreras externas que faciliten sobremanera
el manejo de imgenes y videos de manera suciente-
mente transparente para el usuario, como es el caso
de PIL y OpenCV; y todo esto en su conjunto debe
hacer uso de las librerias que proporciona la SDK de
NVIDIA. En la gura 2 se representan de manera
clara estas dependencias de software.
B. Ejecucin de un kernel con PyCUDA
No existe una nica manera de ejecutar un algorit-
mo en un dispositivo con PyCUDA y, por supuesto,
no todas resultan igual de ecientes. A continuacin,
se mostrar una sencilla secuencia de instrucciones
que ilustran de manera bastante exacta el nivel
de abstraccin que puede llegar a alcanzarse sin
menoscabo de la eciencia.
En primer lugar, se importan los mnimos paquetes
necesarios para el funcionamiento de PyCUDA:
i mport pycuda . autoinit
i mport pycuda . driver as cuda
from pycuda . compiler
i mport SourceModule
Conviene hacer notar que aunque
[Link] se encarga de inicializar el
dispositivo (seleccionando el de mayor capacidad de
cmputo si hay ms de uno), as como de crear un
contexto automticamente, ambos aspectos pueden
ser congurados manualmente.
El siguiente paso consiste en cargar en memoria
los datos que se desean procesar. En este punto, re-
sulta muy aconsejable el uso del paquete NumPy de
la librera SciPy, pues est provisto del potente tipo
de dato [Link], que facilita la preparacin y
manipulacin de los datos. En este ejemplo, consid-
eraremos dos arrays aleatorios a y b, cuyas compo-
nentes se suman dos a dos sobreescribiendo b con el
resultado.
i mport numpy as np
a = np . random . randn ( 16)
b = np . random . randn ( 16)
Aunque las ms recientes GPUs soportan nmeros
en coma otante de doble precisin, la mayora de
los dispositivos disponibles actualmente slo sopor-
tan precisin simple, por lo que se impone la siguien-
te conversin de tipos:
a . astype ( np . float32 )
b . astype ( np . float32 )
Una vez cargados los datos en memoria, los sigu-
ientes pasos son transferirlos al dispositivo y ejecu-
tar el kernel. Con PyCUDA, ambos pasos pueden
concentrar en uno solo, porque en la propia lla-
mada al kernel puede estar implcita la transferen-
cia de los datos a la memoria del dispositivo si se
hace uso de la clase ArgumentHandler disponible en
[Link], la cual est preparada para trabajar
con arrays numpy como argumentos de entrada/sal-
ida.
kernel = SourceModule ( " " "
__global__ voi d name( f l o a t *a ,
f l o a t *b) {
i nt i dx = threadI dx . x ;
b [ i dx ] = b [ i dx ] + a [ i dx ] ;
}
" " " )
f = kernel . get_function ( " name" )
f( cuda . In( a ) , cuda . InOut ( b ) ,
block =(16 , 16 , 1))
C. Overhead inducido
Obviamente, el hecho de trabajar con un lenguaje
interpretado como lo es Python, y con un wrapper
como lo es PyCUDA, implica una carga de trabajo
extra para el procesador (no directamente relaciona-
do con el cmputo en GPU) que debe ser analizada
y comparada con la misma ejecucin nominal en C
para determinar si este overhead supone un grava-
men aceptable o no. En la gura 3 se puede observar
una comparacin al ejecutar un ltro de convolucin
separable [5] tanto en C como en Python + PyCU-
DA, separando en cada caso (para distintos tamaos
de matrices cuadradas) el tiempo empleado en eje-
cutar nicamente el kernel en GPU y el programa
completo (que engloba reserva de memoria, creacion
de los arrays aleatorios, instanciacion del kernel, lib-
eracion de memoria... as como el tiempo de ejecu-
cin del propio kernel en la GPU). Como se puede
observar, y como era de esperar, los kernels se ejecu-
tan siempre ligeramente ms rpidos en C (un 50 %
ms rpido como mnimo, aunque hay que recordar
que en estos niveles se habla de milisegundos para
procesar matrices cuadradas del orden de 2048x2048
elementos). Sin embargo, en el tiempo total de ejecu-
cin se puede observar como lo que a priori debera
ser una ventaja para C, a partir de 2048x2048 ele-
mentos el programa en C tarda de hecho ms que el
mismo programa en Python. Esto puede deberse a
Fig. 3. Kernel para un ltro de convolucin: C y PyCUDA
diversas razones: en C, los arrays a procesar se re-
llenan con nmeros aleatorios obtenidos mediante la
funcin rand(), mientras que en Python es NumPy
el encargado de generar las matrices aleatorias. Es
conocida la gran eciencia de NumPy a la hora de
manejar matrices de gran tamao, por lo que este de-
talle puede jugar a su favor. Otro posible punto de
divergencia (ya que aunque los programas sean fun-
cionalmente iguales, evidentemente hay ciertos ele-
mentos del lenguaje que estn programados de for-
ma distinta) sea la utilizacin de los timers propios
de NVIDIA para realizar las medidas en C (a travs
de la librera proporcionada por la SDK shrUtils);
sera interesante comprobar hasta que punto estn o
no interriendo estos timers particulares en las medi-
ciones totales.
En cualquier caso, puede comprobarse como el
overhead que introduce la utilizacin de Python +
PyCUDA no es, en ningn caso, alarmante. S que
es necesario hacer notar, sin embargo, que en el caso
de las primeras ejecuciones de algn programa que
use PyCUDA, la fase de carga de los import iniciales
s que es importante, llegando a tardar los mismos
ejemplos de la gura 3 cerca de 2 segundos, y donde
la mayora de los cuales se emplea en la precarga de
estas directivas del wrapper: comunicacin inicial con
el/los dispositivos existentes, seleccin de dispositi-
vo, carga de la interfaz con el compilador de NVIDIA
nvcc, etc.
IV. Producto matricial
La manera tradicional de abordar la multiplicacin
de matrices pasa por ejecutar un algoritmo secuen-
cial de complejidad casi cbica en las mejores imple-
mentaciones. Su versin paralela, en cambio, permite
el clculo simultneo de las las de la primera matriz
multiplicando con la correspondiente columna de la
segunda para formar el resultado.
BLAS (Basic Linear Algebra Subprograms) es, de
facto, una interfaz estndar de programacin de li-
breras que realizan operaciones bsicas de lgebra
lineal con vectores y/o matrices.
Desde su primera publicacin, en 1979, numerosos
fabricantes de hardware han desarrollado versiones
altamente optimizadas de BLAS. Tambin NVIDIA
lo ha incluido en el SDK de CUDA para proporcionar
Fig. 4. Producto de matrices en CUDA: C y PyCUBLAS
una versin de altas prestaciones para estas opera-
ciones. Dicha implementacin ha sido denominada
CUBLAS.
Por su parte, PyCUBLAS es un wrapper [6] de
Python para CUBLAS creado por Derek Anderson
que ha centrado su diseo en la multiplicacin de
grandes matrices. Dispone, adems, de las ventajas
ya comentadas de Python en cuanto a abstraccin,
lo que posibilita la ejecucin de una operacin con
muy pocas lneas de cdigo.
i mport numpy as np
from pycublas i mport CUBLASMatrix
a = np . random . randn ( width , length ) .
astype ( np . float32 )
b = np . random . randn ( width , length ) .
astype ( np . float32 )
a = CUBLASMatrix ( np . mat ( a ) )
b = CUBLASMatrix ( np . mat ( b ) )
c = a * b
Esta sencillez sintctica podra ser atractiva para
extender el uso de CUDA entre investigadores de
otras ciencias cuyos estudios precisen de la manip-
ulacin de cantidades masivas de datos.
En esta seccin se confrontan el tiempo de ejecu-
cin en el dispositivo de una multiplicacin de ma-
trices cuadradas de diferentes dimensiones, tanto a
travs de PyCUBLAS como de su correspondiente
versin nativa en C. No se ha contemplado en la gr-
ca de la gura 4 los tiempos de ejecucin en la CPU,
puesto que estos llegan a ser hasta 35 millones de ve-
ces mayor en el caso de una matrix de 2048x2048.
V. Deteccin de movimiento
Teniendo en cuenta las posibilidades del modelo
CUDA exploradas hasta ahora, parece lgico buscar
algn algoritmo que conlleve un esfuerzo computa-
cional notable para ir un paso ms all en la explo-
racin del uso de Python como vehculo conductor
de los programas de cmputo. Una primera conside-
racin interesante es el RANSAC [7], un algoritmo
utilizado frecuentemente en campos muy diversos,
pero no resulta fcilmente acomodable al cmputo
Fig. 5. Jerarqua de clases del detector de movimiento
paralelo bajo esta arquitectura debido a que requiere
de estructuras de datos complejas que adems con-
templan mltiples dependencias entre ellas.
Finalmente, se ha escogido como objetivo de desar-
rollo el diseo e implementacin de un paquete que
permita aplicar diferentes ltros a una imagen, a un
conjunto de imgenes o a un video, en cuyo caso ser
descompuesto en sus correspondientes frames. Este
paquete puede utilizarse para acelerar el clculo de
aplicaciones complejas que requieran de la aplicacin
de ltros [8]. En concreto, una de las ms interesantes
consiste en un programa de deteccin de movimien-
to: a grandes rasgos, toma 2 frames de un video y
discierne (marcando en color rojo sobre uno de los
frames original) las partes en movimiento entre los
mismos. Esto mismo se ejecuta de manera iterativa
el nmero de veces necesario para realizar la detec-
cin de movimiento sobre un video compuesto de una
multitud de frames.
El paquete Filters desarrollado para este n se
estructura, esencialmente, en torno a dos clases:
CUDAHandler, concebido para abstraer de muchos
detalles de la comunicacin con la GPU (informal-
mente, podra considerarse un wrapper del propio Py-
CUDA); y Filter, clase abstracta de la que heredan
cada uno de los ltros implementados. En la gu-
ra 5, pueden observarse tres clases hijas de Filter
que contienen las instrucciones para gestionar tres
ltros necesarios para la deteccin de movimiento
(Dierence, Threshold y Erosion), como se explica en
la posterior subseccin. Tambin se contempla una
clase MotionDetector, encargada de dirigir la detec-
cin en s aplicando los ltros frame tras frame y que
hace uso del paquete Filters, adems por ltimo de
la clase VideoHandler que la abstrae de la manipu-
lacin de las operaciones de gestin de vdeo.
A. Implementacin del algoritmo
El algoritmo de deteccin de movimiento ms sim-
ple se basa en la aplicacin de una secuencia de l-
tros sobre los frames (imgenes) del video [9]. Para
entender el proceso basta con escoger 2 frames con-
secutivos del video y aplicar los siguientes pasos:
1. Conversin a escala de grises de las 2 imgenes
2. Aplicacin del ltro de diferencia a las 2 im-
genes
3. Aplicacin del ltro Threshold
4. Aplicacin del ltro de Erosin
5. Mezcla en el canal R de la imagen original con
la imagen resultado de los ltros
Una vez obtenidos las 2 imgenes en escala de gris-
es, se procede a aplicar el primer ltro:
Filtro de Diferencia: Este ltro consiste en el
valor absoluto de la resta de cada pxel (restando
canal a canal en caso de imgenes de varios canales)
de las dos imgenes. Con esto obtenemos las zonas
donde se ha producido movimiento, como se puede
observar en la primera imagen de la gura 6.
Filtro Threshold: La nalidad de este ltro es
obtener una imagen binaria donde solo aparecen px-
eles blancos o negros. Este ltro compara cada pxel
con un umbral, y si el valor del pxel est por debajo
se asigna el valor 0 (negro), en caso contrario (por
encima del umbral) se asigna el valor 255 (blanco).
As pues, la imagen resultante quedara como la se-
gunda imagen de la gura 6, donde adems se aprecia
la aparicin de ruido a simple vista.
Filtro de Erosin: Contenido dentro los llama-
dos Filtros Morfolgicos, este ltro determina si un
pxel se mantiene (se dene como blanco) o se elimi-
na (se dene como negro). Para sopesar esta decisin
se hace uso de una mscara (denida a conveniencia)
que determina los pxeles vecinos a examinar; desde
que al menos uno de estos vecinos est en negro, se
elimina el pxel analizado (operacin and lgica. Por
el contrario, si todos los pxeles vecinos existen el px-
el analizado permanecer en blanco. El objetivo de
aplicar este ltro es eliminar el ruido expuesto por el
ltro anterior, como se puede apreciar en la tercera
Fig. 6. Fases del algoritmo de deteccin de movimiento
imagen de la gura 6.
Por ltimo, queda realizar el fundido en el canal
R de la imagen original con la imagen resultante de
aplicar el ltro de erosin. Este fundido no es ms que
una suma de pxel a pxel, obteniendo as el resultado
nal de la gura 6.
VI. Conclusiones
Como se ha podido observar, implementar la re-
solucin de problemas relativamente complejos no
es especialmente costoso en tiempo con lenguajes
dinmicos como Python. Si a eso se le aade la posi-
bilidad de utilizar todo el potencial de cmputo pa-
ralelo que ofrece CUDA a travs de wrappers como
PyCUDA, el resultado es una herramienta muy po-
tente que puede satisfacer las necesidades de investi-
gadores y cientcos en general tanto por madurez de
la misma como por rendimiento, a cambio de un pe-
queo e inevitable overhead inherente a la naturaleza
interpretada de Python y al uso de wrappers. De
cualquier forma, ese incremento en tiempo es lo su-
cientemente despreciable para que se pueda ignorar
sin temor, mxime si se tiene en cuenta el hecho de
que a mayor tamao del problema, ms impercepti-
ble se torna dicha carga de trabajo adicional. Por l-
timo, pero no por ello menos importante, los autores
desean recalcar que la curva de aprendizaje nece-
saria para poder manejarse en este entorno con cier-
ta solvencia es considerablemente ms suave que la
que conlleva el entorno tradicional de programacin
de CUDA bajo C/C++, lo cual consideran un ar-
gumento de suma importancia para atraer usuarios
potenciales, ya sean acadmicos de nueva hornada
o investigadores asentados que tienen necesidad de
clculo masivo paralelo y que utilizan para ello apli-
caciones desarrolladas hace aos en lenguajes como
FORTRAN cuyo mantenimiento se hace cada vez
ms inviable. En denitiva, si se tiene intencin de
migrar estas aplicaciones, Python y PyCUDA con-
forman una alternativa perfectamente capaz.
Referencias
[1] Andreas Klckner, Nicolas Pinto, Yunsup Lee, Bryan C.
Catanzaro, Paul Ivanov, and Ahmed Fasih, ``Pycuda:
Gpu run-time code generation for high-performance com-
puting,'' CoRR, vol. abs/0911.3456, 2009.
[2] Khronos Group, ``OpenCL - The open standard for par-
allel programming of heterogeneous systems,'' 2011.
[3] NVIDIA Corp., ``What is CUDA - NVIDIA Developer
Zone,'' 2011.
[4] NVIDIA Corp., ``NVIDIA CUDA C Best Practices
Guide,'' 2010.
[5] Victor Podlozhnyuk (NVIDIA Corp.), ``Image Convolu-
tion with CUDA,'' 2007.
[6] Derek Anderson, ``PyCUBLAS - Easy
Python/NumPy/CUDA/CUBLAS Integration,'' 2009.
[7] Liu Jiayin, Wang Chuang, and Jae Ho Kim, ``Camera mo-
tion detection for conversation scenes in movies,'' in Pro-
ceedings of the 2010 International Conference on Compu-
tational and Information Sciences, Washington, DC, USA,
2010, ICCIS '10, pp. 725--728, IEEE Computer Society.
[8] Zhiyi Yang, Yating Zhu, and Yong Pu, ``Parallel image
processing based on cuda,'' in CSSE (3). 2008, pp. 198--
201, IEEE Computer Society.
[9] Andrew Kirillov, ``Motion detection algorithms,'' 2007.