¿Cómo escriben las personas pruebas automatizadas para sus algoritmos estocásticos?

Si desea _unitar_ probar un algoritmo aleatorio, necesita implementarlo de tal manera que pueda especificar cuáles serán los valores “aleatorios” para cualquier uso dado. La mejor manera de hacerlo varía según el paradigma del lenguaje en el que esté implementando su algoritmo, pero el tema general es implementar el algoritmo de tal manera que se pueda anular la fuente de valores aleatorios.

Para los idiomas OOP de tipo estático:

  • Nunca llame a un método estático en el cuerpo del algoritmo, analice el uso de:
  • Inyección de dependencia: su objeto tiene una referencia al objeto que proporciona los valores aleatorios, de esta manera puede crear un objeto auxiliar que devuelve valores especificados (también considere usar bibliotecas simuladas), o
  • Delegación: su algoritmo llama a otro método en su objeto para obtener el valor aleatorio, de esta manera en sus pruebas puede heredar y anular este método a un valor para el cual conoce el valor de retorno del algoritmo cuando se utiliza este valor “aleatorio”

Para los lenguajes de tipo dinámico (donde las clases, las funciones y los módulos son objetos de primera clase), tiene los enfoques anteriores para usar, además de:

  • Monkey parchea la clase / módulo que proporciona los valores aleatorios para devolver los valores que desea. Tenga en cuenta que siempre debe deshacer todos los parches o podría comenzar a afectar otras pruebas (aunque muchas bibliotecas burlonas lo harán automáticamente. Los métodos estáticos son menos problemáticos en los lenguajes dinámicos, ya que puede cambiar lo que existe en el espacio de nombres en el fly, donde al igual que con los lenguajes estáticos no hay forma de cambiar “x = 4 + random.uniform ()” para no llamar al método real random.uniform ().

Tenga en cuenta que esta sería la misma respuesta si la pregunta hubiera sido “¿cómo puedo unir el código de prueba que utiliza una conexión de base de datos?”. Respuesta: abstraiga las dependencias para que pueda modificarlas.

Ahora, algunos recomendarían que simplemente establezca la semilla aleatoria, ya que esto proporcionará un conjunto determinista de valores de un conjunto de funciones aleatorias. Sin embargo, esto conducirá a pruebas frágiles:

  • La prueba no proporciona explícitamente todas sus entradas, ya que algunas de ellas están envueltas en los métodos aleatorios sembrados. Puede que no esté del todo claro cómo falla una prueba, o peor aún, por qué pasa (cuando no es posible).
  • Todas sus pruebas en consumidores de valores aleatorios dependerán del orden, ya que la prueba ejecutada x necesita recibir el valor y del método aleatorio, y si se cambia el orden de la prueba, otra prueba recibirá el valor y. Esto tiene el efecto secundario indeseable de que las personas se volverán reacias a agregar más pruebas, ya que corre el riesgo de cambiar el orden de ejecución de la prueba, lo que provocará que las pruebas fallen por razones que no son evidentes.

Finalmente, hay dos enfoques para las pruebas funcionales de una aplicación estocástica que uso, y recomendaría que considere usar ambos si es posible.

El primero es elegir un conjunto de entradas, así como una semilla aleatoria predefinida y registrar las salidas. Escriba una prueba que ejecute la funcionalidad en cuestión y verifique que los resultados sean los resultados esperados. Es posible que haya notado que acabo de recomendarle que escriba una prueba de una manera que previamente recomendé evitar, sin embargo, la diferencia aquí es que las pruebas funcionales no sufren de la misma manera el enfoque de semillas aleatorias que las pruebas unitarias.

Las pruebas funcionales son casi siempre frágiles y difíciles de depurar, incluso sin aleatoriedad en la mezcla. Además, por definición, tendrá menos pruebas funcionales que pruebas unitarias, ya que tendrá menos ‘funcionalidad’ que las ‘unidades’ que lo implementan (y si esto no es cierto, tiene que refactorizar mucho) . Respaldar pruebas frágiles de uno o dos dígitos es mucho más fácil que soportar cientos o miles de pruebas unitarias frágiles. También debe tener cuidado con el pedido, pero puede resolverlo ejecutando las pruebas individualmente (en sus propios procesos). Esto requeriría mucho tiempo para un gran volumen de pruebas, pero nuevamente, no tendrá un alto volumen de pruebas funcionales.

La segunda opción es mucho más complicada de implementar correctamente (y propensa a errores) pero le brinda una mejor seguridad de que la aleatorización real funciona como lo espera. En resumen, usted define la distribución de resultados que espera para una entrada o entradas explícitas, llama a la funcionalidad con estas entradas repetidamente por un número predefinido de veces que retiene todos los resultados y finalmente verifica que todos los resultados ‘ajustar’ la distribución esperada dentro de cierta tolerancia. Esto es complicado, ya que debe tener una comprensión muy profunda de sus algoritmos a un alto nivel para determinar una distribución precisa de los resultados, y calcular un recuento de iteraciones y tolerancia que no es excesivamente excesivo pero que aún proporciona resultados significativos También puede resultar difícil. Tendrá fallas periódicas debido al conjunto patológico ocasional de valores aleatorios (su frecuencia dependerá de la elección de las iteraciones y la tolerancia), y probablemente también desee implementar algún tipo de contabilidad para que cuando fallan pueda ver qué entradas causaron la distribución inesperada de resultados. Sin embargo, a pesar de todos estos inconvenientes, este estilo de pruebas es la única forma de ejercer explícitamente el (los) algoritmo (s) en cuestión y demostrar que funcionan como se espera en una situación del “mundo real”.

Peter Norvig, director de investigación de Google, tiene un capítulo en “Codificadores en el trabajo” donde analiza las limitaciones de las metodologías de prueba unitarias existentes para representar restricciones suaves en el software. Por ejemplo, es posible que desee que su algoritmo de Monte Carlo esté dentro de una precisión dada, pero también puede querer que termine de ejecutarse dentro de un período de tiempo finito. Los metodólogos de pruebas actuales no admiten muy bien las restricciones blandas. Es por eso que Google no realiza pruebas unitarias para sus algoritmos de búsqueda y aprendizaje automático.

http://amzn.to/9YciJX

Lo que haría para probar un algoritmo estocástico es generar puntos de datos a partir de una distribución conocida donde sepa qué respuesta espera del algoritmo. Por ejemplo, si su algoritmo intenta estimar la media de una muestra, genere muestras a partir de una distribución gaussiana con una media conocida y vea si la salida de su algoritmo se encuentra dentro de límites razonables.

Puede ejecutar el algoritmo para n conjuntos de entrada y tener restricciones que dicen “La media estimada por el algoritmo debe estar dentro de 2 desviaciones estándar de la media para esta cantidad de pruebas”. La prueba unitaria puede dar falsos negativos con poca probabilidad, pero detectaría errores la mayor parte del tiempo.

Sin embargo, lo mejor que puede hacer es no realizar pruebas unitarias, sino cuantificar y registrar el rendimiento de su algoritmo en su conjunto de datos real y conjuntos de datos simulados. Eso le brinda información sobre cuándo funcionan sus algoritmos y cuándo fallan, y sobre en qué debe concentrarse el esfuerzo para obtener la mejor mejora en los resultados con el menor esfuerzo.

Las pruebas de su unidad y si su componente de software las supera solo debería ser una función de las entradas y salidas en la interfaz de usuario. La modificación de la base de código interna del componente para realizar pruebas unitarias tiene una sobrecarga extremadamente grande y parece contrario al objetivo de verificar que el componente de software funciona como componente de un sistema.

No estoy haciendo esto ahora, aunque consideraría adoptar un enfoque probabilístico. Al ejecutarlo, ¿podría esperar un cierto tipo de resultado? Es posible que solo detecte regresiones masivas donde su algoritmo oscila enormemente fuera de rango, pero es mejor que nada.

Además, si corrige los datos de entrada, “sabe” cuál es la respuesta correcta. Y si el algoritmo falla alguna vez, o varias veces, hay motivos para preocuparse.

More Interesting

¿Cuáles son las diferentes técnicas para el procesamiento del lenguaje natural para resolver un ensayo de clasificación automática?

¿El aprendizaje supervisado se usa más?

¿Una red neuronal necesita un nodo de salida para cada cosa que pueda clasificar?

Durante el aprendizaje automático para la detección de objetos, ¿cómo puedo simular el efecto de la iluminación de diferentes días en mi conjunto de datos de entrenamiento?

¿Hay alguna debilidad en el uso de la agrupación máxima y la agrupación promedio?

¿Cuál es un buen conjunto de datos para probar mi clasificador vecino más cercano K?

¿Cuál es la forma más rápida de aprender matemáticas para el aprendizaje automático y el aprendizaje profundo?

¿Las herramientas como BigML o Google Prediction API dejarán a los expertos en aprendizaje automático fuera del trabajo?

¿Puede un principiante de programación sumergirse profundamente en el aprendizaje automático y el aprendizaje profundo directamente?

Cómo aprender y construir un chatbot inteligente basado en inteligencia artificial como Google Allo desde cero, con un mayor enfoque en el modelo de dominio cerrado basado en la recuperación y el aprendizaje de ML y NLP

¿Necesito visión artificial para leer texto simple en imágenes?

¿Cómo pueden beneficiarse los MOOC de sus datos?

Como estudiante universitario de ciencias de la computación, cuál es la mejor opción entre cs o estadísticas Ph.D. para la carrera de ciencia de datos?

¿Cómo se usa la pérdida de peso para la regularización en las redes neuronales?

¿Qué es un uso subestimado del aprendizaje automático?