El consenso de muestra aleatoria ( RANSAC ) es un método iterativo para estimar parámetros de un modelo matemático a partir de un conjunto de datos observados que contienen valores atípicos , cuando a los valores atípicos no se les debe otorgar ninguna influencia [ aclarar ] en los valores de las estimaciones. Por lo tanto, también se puede interpretar como un método de detección de valores atípicos. [1] Es un algoritmo no determinista en el sentido de que produce un resultado razonable solo con una cierta probabilidad, y esta probabilidad aumenta a medida que se permiten más iteraciones. El algoritmo fue publicado por primera vez por Fischler y Bolles en SRI International en 1981. Utilizaron RANSAC para resolver el problema de determinación de ubicación (LDP), donde el objetivo es determinar los puntos en el espacio que se proyectan sobre una imagen en un conjunto de puntos de referencia con ubicaciones conocidas.
RANSAC utiliza submuestreo aleatorio repetido . [2] Una suposición básica es que los datos consisten en "inliers", es decir, datos cuya distribución puede explicarse por algún conjunto de parámetros del modelo, aunque pueden estar sujetos a ruido, y "outliers", que son datos que no se ajustan al modelo. Los outliers pueden provenir, por ejemplo, de valores extremos del ruido o de mediciones erróneas o hipótesis incorrectas sobre la interpretación de los datos. RANSAC también supone que, dado un conjunto (normalmente pequeño) de inliers, existe un procedimiento que puede estimar los parámetros de un modelo que explique o ajuste de forma óptima estos datos.
Un ejemplo simple es ajustar una línea en dos dimensiones a un conjunto de observaciones. Suponiendo que este conjunto contiene tanto inliers , es decir, puntos que aproximadamente se pueden ajustar a una línea, como outliers , puntos que no se pueden ajustar a esta línea, un método simple de mínimos cuadrados para el ajuste de línea generalmente producirá una línea con un mal ajuste a los datos, incluidos los inliers y los outliers. La razón es que se ajusta de manera óptima a todos los puntos, incluidos los outliers. RANSAC, por otro lado, intenta excluir los outliers y encontrar un modelo lineal que solo use los inliers en su cálculo. Esto se hace ajustando modelos lineales a varias muestras aleatorias de los datos y devolviendo el modelo que tiene el mejor ajuste a un subconjunto de los datos. Dado que los inliers tienden a estar más relacionados linealmente que una mezcla aleatoria de inliers y outliers, un subconjunto aleatorio que consiste completamente en inliers tendrá el mejor ajuste del modelo. En la práctica, no hay garantía de que se muestree aleatoriamente un subconjunto de valores inliers, y la probabilidad de éxito del algoritmo depende de la proporción de valores inliers en los datos, así como de la elección de varios parámetros del algoritmo.
El algoritmo RANSAC es una técnica de aprendizaje para estimar los parámetros de un modelo mediante un muestreo aleatorio de los datos observados. Dado un conjunto de datos cuyos elementos de datos contienen tanto valores atípicos como valores atípicos, RANSAC utiliza el esquema de votación para encontrar el resultado de ajuste óptimo. Los elementos de datos del conjunto de datos se utilizan para votar por uno o varios modelos. La implementación de este esquema de votación se basa en dos supuestos: que las características ruidosas no votarán de manera consistente por ningún modelo individual (pocos valores atípicos) y que hay suficientes características para concordar en un buen modelo (pocos datos faltantes). El algoritmo RANSAC se compone esencialmente de dos pasos que se repiten iterativamente:
El conjunto de valores inertes obtenidos para el modelo de ajuste se denomina conjunto de consenso . El algoritmo RANSAC repetirá iterativamente los dos pasos anteriores hasta que el conjunto de consenso obtenido en cierta iteración tenga suficientes valores inertes.
La entrada del algoritmo RANSAC es un conjunto de valores de datos observados, un modelo para ajustar las observaciones y algunos parámetros de confianza que definen los valores atípicos. En más detalles que la descripción general del algoritmo RANSAC antes mencionada, RANSAC logra su objetivo repitiendo los siguientes pasos:
Para converger a un conjunto de parámetros de modelo suficientemente bueno, este procedimiento se repite un número fijo de veces, produciendo cada vez el rechazo de un modelo porque muy pocos puntos forman parte del conjunto de consenso, o un modelo refinado con un tamaño de conjunto de consenso mayor que el conjunto de consenso anterior.
El algoritmo genérico RANSAC funciona como el siguiente pseudocódigo :
Dado: datos – Un conjunto de observaciones. modelo – Un modelo para explicar los puntos de datos observados. n – El número mínimo de puntos de datos necesarios para estimar los parámetros del modelo. k – El número máximo de iteraciones permitidas en el algoritmo. t – Un valor umbral para determinar los puntos de datos que se ajustan bien al modelo (inlier). d – El número de puntos de datos cercanos (inliers) necesarios para afirmar que el modelo se ajusta bien a los datos.Devolver: bestFit: los parámetros del modelo que pueden ajustarse mejor a los datos (o nulos si no se encuentra un buen modelo).iteraciones = 0bestFit = nulobestErr = algo realmente grande // Este parámetro se utiliza para afinar los parámetros del modelo para obtener el mejor ajuste de datos a medida que avanzan las iteraciones.mientras las iteraciones < k lo hagan maybeInliers := n valores seleccionados aleatoriamente de los datos maybeModel := parámetros del modelo ajustados a maybeInliers confirmadoInliers := conjunto vacío para cada punto en los datos , si el punto se ajusta a maybeModel con un error menor que t, entonces añadir punto a confirmInliers fin si fin para si el número de elementos en answeredInliers es > d entonces //Esto implica que quizás hayamos encontrado un buen modelo. //Ahora prueba lo bueno que es. betterModel := parámetros del modelo ajustados a todos los puntos en answeredInliers thisErr := una medida de qué tan bien betterModel se ajusta a estos puntos Si esteErr < mejorErr entonces mejorAjuste := mejorModelo mejorErr := esteErr fin si fin si iteraciones de incrementoterminar mientrasDevolver bestFit
Una implementación de Python que refleja el pseudocódigo. También define un método LinearRegressor
basado en mínimos cuadrados, se aplica RANSAC
a un problema de regresión 2D y visualiza el resultado:
desde copiar importar copiar importar numpy como np desde numpy.random importar default_rng rng = default_rng ()clase RANSAC : def __init__ ( self , n = 10 , k = 100 , t = 0.05 , d = 10 , model = None , loss = None , metric = None ): self . n = n # `n`: Número mínimo de puntos de datos para estimar parámetros self . k = k # `k`: Máximo de iteraciones permitidas self . t = t # `t`: Valor de umbral para determinar si los puntos se ajustan bien self . d = d # `d`: Número de puntos de datos cercanos necesarios para afirmar que el modelo se ajusta bien self . model = model # `model`: clase que implementa `fit` y `predict` self . loss = loss # `loss`: función de `y_true` e `y_pred` que devuelve un vector self . metric = metric # `metric`: función de `y_true` e `y_pred` y devuelve un float self . mejor_ajuste = Ninguno self . mejor_error = np . inf def fit ( self , X , y ) : para _ en rango ( self.k ) : ids = rng.permutation ( X.shape [ 0 ] ) tal vez_inliers = ids [: self . n ] tal vez_modelo = copy ( self . modelo ) . fit ( X [ tal vez_inliers ], y [ tal vez_inliers ]) umbralizado = ( self . loss ( y [ ids ][ self . n :], maybe_model . predict ( X [ ids ][ self . n :])) < self . t ) inlier_ids = ids [ self . n :][ np . flatnonzero ( con umbral ) . flatten ()] si inlier_ids . size > self . d : inlier_points = np . hstack ([ maybe_inliers , inlier_ids ]) mejor_modelo = copy ( self . model ) . fit ( X [ inlier_points ], y [ inlier_points ]) este_error = self . metric ( y [ puntos_inferiores ], better_model . predict ( X [ puntos_inferiores ]) ) si este_error < self . mejor_error : self . mejor_error = este_error self . mejor_ajuste = mejor_modelo volver a sí mismo def predict ( self , X ) : devuelve self.best_fit.predic ( X )def square_error_loss ( y_verdadero , y_pred ): return ( y_verdadero - y_pred ) ** 2def error_cuadrado_medio ( y_verdadero , y_pred ): devuelve np . suma ( pérdida_error_cuadrado ( y_verdadero , y_pred )) / y_verdadero . forma [ 0 ]clase LinearRegressor : def __init__ ( self ): self . params = None def fit ( self , X : np.ndarray , y : np.ndarray ) : r , _ = X.forma X = np.hstack ( [ np.ones ( ( r , 1 ) ) , X ] ) self.params = np.linalg.inv ( X.T@X ) @ X.T @ y return self def predict ( self , X : np.ndarray ) : r , _ = X.shape X = np.hstack ( [ np.ones ( ( r , 1 ) ) , X ] ) return X @ self.params si __nombre__ == "__principal__" : regresor = RANSAC ( modelo = LinearRegressor (), pérdida = square_error_loss , métrica = half_square_error ) X = np . matriz ([ - 0,848 , - 0,800 , - 0,704 , - 0,632 , - 0,488 , - 0,472 , - 0,368 , - 0,336 , - 0,280 , - 0,200 , - 0,00800 , - 0,0840 , 0,0240 , 0,100 , 0,124 , 0,148 , 0,232 , 0,236 , 0,324 , 0,356 , 0,368 , 0,440 , 0,512 , 0,548 , 0,660 , 0,640 , 0,712 , 0,752 , 0,776 , 0,880 , 0,920 , 0,944 , - 0,108 , - 0,168 , - 0,720 , - 0,784 , - 0,224 , - 0,604 , - 0,740 , - 0,0440 , 0,388 , - 0,0200 , 0,752 , 0,416 , -0,0800 , -0,348 , 0,988 , 0,776 , 0,680 , 0,880 , -0,816 , -0,424 , -0,932 , 0,272 , -0,556, - 0,568 , - 0,600 , - 0,716 , - 0,796 , - 0,880 , - 0,972 , - 0,916 , 0,816 , 0,892 , 0,956 , 0,980 , 0,988 , 0,992 , 0,00400 ] ) . reshape ( - 1 , 1 ) y = np.array ( [ - 0,917 , - 0,833 , - 0,801 , - 0,665 , - 0,605 , - 0,545 , - 0,509 , - 0,433 , - 0,397 , - 0,281 , - 0,205 , - 0,169 , - 0,0531 , - 0,0651 , 0,0349 , 0,0829 , 0,0589 , 0,175 , 0,179 , 0,191 , 0,259 , 0,287 , 0,359 , 0,395 , 0,483 , 0,539 , 0,543 , 0,603 , 0,667 , 0,679 , 0,751 , 0,803 , - 0,265 , - 0,341 , 0,111 , - 0,113 , 0,547 , 0,791 , 0,551 , 0,347 , 0,975 , 0,943 , - 0,249 , - 0,769 , - 0,625 , - 0,861 , - 0,749 , - 0,945 , - 0,493 , 0,163 , - 0,469 , 0,0669 , 0,891 , 0,623 , - 0,609 , - 0,677 , - 0,721 , - 0,745 , - 0,885 , - 0,897 , - 0,969 , - 0,949 , 0,707 , 0,783 , 0,859 , 0,979 , 0,811 , 0,891 , - 0,137 ]) . remodelar ( - 1 , 1 ) regresor . ajuste ( X , y ) importar matplotlib.pyplot como plt plt . style . use ( "seaborn-darkgrid" ) fig , ax = plt . subplots ( 1 , 1 ) ax . set_box_aspect ( 1 ) plt . dispersión ( X , y ) linea = np . linspace ( - 1 , 1 , num = 100 ) . reshape ( - 1 , 1 ) plt . plot ( linea , regresor . predict ( linea ), c = "peru" ) plt . show ()
El valor umbral para determinar cuándo un punto de datos se ajusta a un modelo ( t ), y el número de valores inertes (puntos de datos ajustados al modelo dentro de t ) necesarios para afirmar que el modelo se ajusta bien a los datos ( d ) se determinan en función de los requisitos específicos de la aplicación y el conjunto de datos, y posiblemente en función de una evaluación experimental. Sin embargo, el número de iteraciones ( k ) se puede determinar aproximadamente como una función de la probabilidad de éxito deseada ( p ), como se muestra a continuación.
Sea p la probabilidad deseada de que el algoritmo RANSAC proporcione al menos un resultado útil después de ejecutarse. En casos extremos (para simplificar la derivación), RANSAC devuelve un resultado exitoso si en alguna iteración selecciona solo valores inliers del conjunto de datos de entrada cuando elige n puntos del conjunto de datos a partir del cual se estiman los parámetros del modelo. (En otras palabras, todos los n puntos de datos seleccionados son valores inliers del modelo estimado por estos puntos). Sea p la probabilidad de elegir un valor inlier cada vez que se selecciona un solo punto de datos, es decir, aproximadamente,
Un caso común es que no se conoce bien de antemano debido a un número desconocido de valores atípicos en los datos antes de ejecutar el algoritmo RANSAC, pero se puede dar un valor aproximado. Con un valor aproximado dado de y asumiendo aproximadamente que los n puntos necesarios para estimar un modelo se seleccionan de forma independiente (es una suposición aproximada porque cada selección de punto de datos reduce el número de candidatos de puntos de datos para elegir en la siguiente selección en realidad), es la probabilidad de que todos los n puntos sean valores atípicos y es la probabilidad de que al menos uno de los n puntos sea un valor atípico, un caso que implica que se estimará un modelo incorrecto a partir de este conjunto de puntos. Esa probabilidad a la potencia de k (el número de iteraciones en la ejecución del algoritmo) es la probabilidad de que el algoritmo nunca seleccione un conjunto de n puntos que sean todos valores atípicos, y esto es lo mismo que (la probabilidad de que el algoritmo no dé como resultado una estimación exitosa del modelo) en extremo. En consecuencia,
lo cual, después de tomar el logaritmo de ambos lados, conduce a
Este resultado supone que los n puntos de datos se seleccionan de forma independiente, es decir, un punto que se ha seleccionado una vez se reemplaza y se puede seleccionar nuevamente en la misma iteración. A menudo, este no es un enfoque razonable y el valor derivado para k debe tomarse como un límite superior en el caso de que los puntos se seleccionen sin reemplazo. Por ejemplo, en el caso de encontrar una línea que se ajuste al conjunto de datos ilustrado en la figura anterior, el algoritmo RANSAC generalmente elige dos puntos en cada iteración y calcula maybe_model
como la línea entre los puntos y, en ese caso, es fundamental que los dos puntos sean distintos.
Para ganar más confianza, se puede sumar a k la desviación estándar o sus múltiplos . La desviación estándar de k se define como
Una ventaja de RANSAC es su capacidad de hacer una estimación robusta [3] de los parámetros del modelo, es decir, puede estimar los parámetros con un alto grado de precisión incluso cuando hay una cantidad significativa de valores atípicos en el conjunto de datos. Una desventaja de RANSAC es que no hay un límite superior en el tiempo que lleva calcular estos parámetros (excepto el agotamiento). Cuando el número de iteraciones calculadas es limitado, la solución obtenida puede no ser óptima, y puede que ni siquiera sea una que se ajuste bien a los datos. De esta manera, RANSAC ofrece una compensación; al calcular una mayor cantidad de iteraciones, aumenta la probabilidad de que se produzca un modelo razonable. Además, RANSAC no siempre puede encontrar el conjunto óptimo incluso para conjuntos moderadamente contaminados, y generalmente funciona mal cuando la cantidad de valores atípicos es inferior al 50%. RANSAC óptimo [4] se propuso para manejar ambos problemas y es capaz de encontrar el conjunto óptimo para conjuntos muy contaminados, incluso para una proporción de valores atípicos inferior al 5%. Otra desventaja de RANSAC es que requiere el establecimiento de umbrales específicos para cada problema.
RANSAC solo puede estimar un modelo para un conjunto de datos en particular. Como ocurre con cualquier método de un solo modelo cuando existen dos (o más) instancias de modelo, RANSAC puede no encontrar ninguna de ellas. La transformada de Hough es una técnica alternativa de estimación robusta que puede resultar útil cuando hay más de una instancia de modelo. Otro método para el ajuste de múltiples modelos se conoce como PEARL [5] , que combina el muestreo de modelos a partir de puntos de datos como en RANSAC con la reestimación iterativa de valores internos y el ajuste de múltiples modelos se formula como un problema de optimización con una función de energía global que describe la calidad de la solución general.
El algoritmo RANSAC se utiliza a menudo en visión artificial , por ejemplo, para resolver simultáneamente el problema de correspondencia y estimar la matriz fundamental relacionada con un par de cámaras estéreo; consulte también: Estructura a partir del movimiento , transformación de características invariantes de escala , unión de imágenes , segmentación de movimiento rígido .
Desde 1981, RANSAC se ha convertido en una herramienta fundamental en la comunidad de visión artificial y procesamiento de imágenes. En 2006, con motivo del 25º aniversario del algoritmo, se organizó un taller en la Conferencia Internacional sobre Visión Artificial y Reconocimiento de Patrones (CVPR) para resumir las contribuciones y variaciones más recientes del algoritmo original, principalmente destinadas a mejorar la velocidad del algoritmo, la robustez y la precisión de la solución estimada y a reducir la dependencia de las constantes definidas por el usuario.
RANSAC puede ser sensible a la elección del umbral de ruido correcto que define qué puntos de datos se ajustan a un modelo instanciado con un cierto conjunto de parámetros. Si dicho umbral es demasiado grande, entonces todas las hipótesis tienden a ser clasificadas de la misma manera (buenas). Por otro lado, cuando el umbral de ruido es demasiado pequeño, los parámetros estimados tienden a ser inestables (es decir, simplemente agregando o eliminando un dato al conjunto de inliers, la estimación de los parámetros puede fluctuar). Para compensar parcialmente este efecto indeseable, Torr et al. propusieron dos modificaciones de RANSAC llamadas MSAC (M-estimator SAmple and Consensus) y MLESAC (Maximum Likelihood Estimation SAmple and Consensus). [6] La idea principal es evaluar la calidad del conjunto de consenso (es decir, los datos que se ajustan a un modelo y un cierto conjunto de parámetros) calculando su verosimilitud (mientras que en la formulación original de Fischler y Bolles el rango era la cardinalidad de dicho conjunto). Tordoff propone una extensión de MLESAC que tiene en cuenta las probabilidades previas asociadas al conjunto de datos de entrada. [7] El algoritmo resultante se denomina Guided-MLESAC. En la misma línea, Chum propuso guiar el procedimiento de muestreo si se conoce alguna información a priori sobre los datos de entrada, es decir, si es probable que un dato sea un valor atípico o no. El enfoque propuesto se denomina PROSAC, PROgressive SAmple Consensus. [8]
Chum et al. también propusieron una versión aleatoria de RANSAC llamada R-RANSAC [9] para reducir la carga computacional para identificar un buen conjunto de consenso. La idea básica es evaluar inicialmente la bondad del modelo instanciado actualmente utilizando solo un conjunto reducido de puntos en lugar de todo el conjunto de datos. Una estrategia sólida indicará con alta confianza cuándo es el caso de evaluar el ajuste de todo el conjunto de datos o cuándo el modelo puede descartarse fácilmente. Es razonable pensar que el impacto de este enfoque es más relevante en los casos en que el porcentaje de inliers es grande. El tipo de estrategia propuesta por Chum et al. se llama esquema de preempción. Nistér propuso un paradigma llamado RANSAC preemptivo [10] que permite una estimación robusta en tiempo real de la estructura de una escena y del movimiento de la cámara. La idea central del enfoque consiste en generar un número fijo de hipótesis para que la comparación se realice con respecto a la calidad de la hipótesis generada en lugar de con alguna métrica de calidad absoluta.
Otros investigadores intentaron hacer frente a situaciones difíciles en las que no se conoce la escala de ruido y/o hay múltiples instancias de modelos. El primer problema ha sido abordado en el trabajo de Wang y Suter. [11] Toldo et al. representan cada dato con la función característica del conjunto de modelos aleatorios que se ajustan al punto. Luego, los múltiples modelos se revelan como clústeres que agrupan los puntos que respaldan el mismo modelo. El algoritmo de agrupamiento, llamado J-linkage, no requiere la especificación previa del número de modelos ni tampoco necesita el ajuste manual de parámetros. [12]
RANSAC también ha sido diseñado para aplicaciones de estimación de estado recursivo, donde las mediciones de entrada están corrompidas por valores atípicos y los enfoques de filtro de Kalman , que se basan en una distribución gaussiana del error de medición, están condenados al fracaso. Este enfoque se denomina KALMANSAC. [13]