paint-brush
Software para la exploración: lograr el equilibrio en el descubrimientopor@sinavski
333 lecturas
333 lecturas

Software para la exploración: lograr el equilibrio en el descubrimiento

por Oleg SInavski10m2024/03/21
Read on Terminal Reader

Demasiado Largo; Para Leer

Una publicación que defiende: - evitar demasiadas técnicas de producción durante la investigación. La producción y la investigación tienen objetivos diferentes. - Está bien asumir una "deuda tecnológica" en la investigación, ya que la mayor parte del código va a morir. Por ejemplo, no deberías esforzarte por reutilizar el código. - pero como investigador aún deberías invertir en exploración rápida, ramificación rápida y código simple y limpio.
featured image - Software para la exploración: lograr el equilibrio en el descubrimiento
Oleg SInavski HackerNoon profile picture

Trabajé en investigación toda mi vida, por lo que conozco el estereotipo de que los investigadores escriben código feo (por ejemplo, ver aquí , aquí o aquí ). Pero pensé: podemos arreglarlo, ¿verdad? Así que varias veces intenté diseñar buenos marcos de investigación. Intenté incorporar interfaces y crear abstracciones agradables utilizando libros y blogs de ingeniería de software que me gustaba leer.


Pero una y otra vez todos esos esfuerzos fueron en vano. La mayoría del software de investigación en el que trabajé nunca llegó a producción (aunque algunos sí). Habría sido fantástico para mi salud mental si alguien me hubiera dicho una simple verdad: morir el código de investigación es en realidad lo que se supone que debe suceder . En primer lugar, los investigadores no deberían dedicar mucho tiempo a diseñarlo.


Los ingenieros de software profesionales siempre menosprecian a los investigadores que no utilizan las mejores prácticas de software. Hay varias publicaciones que intentan elevar el nivel del código de investigación (por ejemplo, esta excelente publicación y un manual de código de investigación ). Pero esta publicación va al revés: explica cómo no exagerar con las mejores prácticas de software y, en cambio, invertir solo en exploración rápida. Está dirigido a empresas orientadas a la investigación cuyo objetivo es probar muchas ideas rápidamente.

1. Asumir una deuda tecnológica estratégica

Un proyecto de investigación exitoso en una empresa tiene dos fases: exploración y explotación. En la "exploración", desea probar tantas soluciones diversas como pueda. Durante la “explotación” hay que robustecer la mejor solución y convertirla en un producto útil.

Durante la exploración muchos proyectos desaparecen. Debe crear una solución sólida solo durante la explotación.

Las prácticas óptimas de software son bastante diferentes entre los dos. Por eso las empresas suelen tener divisiones de investigación y de productos separadas. Todos los libros que normalmente lee sobre diseño de software tratan principalmente sobre la segunda fase de "explotación". En esta fase, usted está sentando las bases para un producto escalable. Aquí es donde entran todos los patrones de diseño: buenas API, registro, manejo de errores, etc.


Pero en la primera fase de "exploración" no se están construyendo cimientos que perdurarán para siempre. De hecho, si la mayoría de tus esfuerzos sobreviven, entonces (por definición) no exploraste lo suficiente.


Muchas de las prácticas descritas en esta publicación son ejemplos de lo que normalmente se convertiría en "deuda tecnológica". Es lo que se obtiene al no escribir código limpio, reutilizable y bien abstracto. ¿La deuda es siempre mala? Preferimos no obtener nunca un préstamo o una hipoteca, pero pedir dinero prestado suele ser una buena estrategia en la vida. Está bien endeudarse para actuar rápido y obtener ganancias más adelante.

Está bien endeudarse en software durante la investigación; no es necesario pagarlo todo, sólo la minoría que se encuentra en caminos de investigación exitosos.

Del mismo modo, al no endeudarse técnicamente, podría estar ralentizando su investigación. La buena noticia es que la mayoría de las veces no tendrás que devolverlo. Es probable que la mayor parte de su código de investigación muera de todos modos. Entonces, en promedio, no sufrirá toda la deuda tecnológica que ha contraído.

El caso contra la reutilización de código

Muchas arquitecturas de software y técnicas de refactorización están orientadas específicamente a mejorar la reutilización del código. Existen desventajas genéricas en la reutilización de código. Pero en producción se ven superados por los conocidos beneficios (ver por ejemplo este típico post ). En los proyectos de investigación, la mayor parte del código está destinado a hundirse en el olvido. Esforzarse por reutilizar el código podría ralentizarlo.


Limitar la reutilización de código es el tipo de deuda técnica que se puede asumir en la investigación. Hay varios patrones de reutilización de código que quiero analizar: agregar una dependencia innecesaria, copiar y pegar código, mantener una gran cantidad de código de investigación compartido, inversiones prematuras en diseño.

Piénselo dos veces antes de importar algo nuevo

Si conoce una biblioteca versionada en buen estado que le permitirá acelerar, ¡adelante! Pero antes de asumir una nueva dependencia, trate de evaluar si vale la pena. Cada uno adicional te acerca al infierno de la dependencia. Le hace invertir tiempo en aprenderlo y solucionarlo. Vea más peligros de las dependencias en esta publicación concisa .


Probablemente esté bien depender de algo si:

  • Ya lo usaste, no hay mucho que aprender, tiene una gran comunidad, buenos documentos y pruebas.
  • está versionado, fácil de instalar
  • y finalmente, no hay manera de que puedas implementarlo tú mismo.

Pero tenga cuidado con una dependencia si:

  • no sabes cómo usarlo rápidamente, es muy nuevo (o muy viejo) o nadie parece saberlo; no hay documentos ni pruebas

  • es de tu monorepo y otros equipos lo cambian constantemente

  • incorpora muchas otras dependencias y herramientas; o simplemente es difícil de instalar

  • y finalmente, siente que usted (o algún LLM) puede escribir este código en unas pocas horas.


En lugar de una dependencia explícita, puedes seguir un bonito proverbio de Go: " un poco de copia es mejor que un poco de dependencia ", que es nuestro siguiente tema.

Copiar y pegar te da libertad de experimentación

Copiar y pegar es rápido y, a veces, es la mejor herramienta durante la investigación.

Algunos dicen que “ copiar y pegar debería ser ilegal ”. Pero, para mi sorpresa, me encontré argumentando a favor de ello con bastante frecuencia. Copiar y pegar podría ser la opción óptima durante la fase de exploración.


Si depende de una función muy utilizada de otra parte del código base, puede olvidarse de cambiarla fácilmente. Es probable que le rompas algo a alguien y tengas que dedicar un tiempo precioso a revisar y corregir el código. Pero si copias y pegas el código necesario en tu carpeta, eres libre de hacer lo que quieras con él. Esto es muy importante en proyectos de investigación donde la experimentación es una norma y no una excepción. Especialmente si no estás seguro de si los cambios van a ser útiles para todos.


Encuentro que las bases de código de aprendizaje profundo son las más adecuadas para copiar y pegar. Normalmente, la cantidad de código necesaria para describir un modelo y su entrenamiento no es tan grande. Pero al mismo tiempo podría tener muchos matices y ser difícil de generalizar. Los guiones de entrenamiento que se pueden compartir tienden a crecer hasta alcanzar un tamaño inmanejable: por ejemplo, Hugging Face transformers Trainer tiene +4k líneas. Curiosamente, los transformadores optaron por copiar y pegar a nivel de modelo. Consulte su publicación con el razonamiento detrás de su política de "modelo de archivo único". Vea más recursos sobre la belleza de copiar y pegar al final.


Una alternativa a copiar y pegar es permanecer en una sucursal. Pero siento que supone demasiado esfuerzo para el trabajo en equipo. Además, encontré varias publicaciones más sobre la belleza de copiar y pegar; vea más publicaciones en la conclusión.

Mantener el código de investigación compartido es difícil

El mantenimiento de código compartido muy utilizado requiere mucho trabajo. Eche un vistazo al número de líneas de archivo torch.nn.Module trazadas con respecto a la versión Pytorch . Se puede ver que incluso los equipos de investigación más avanzados luchan por mantener la complejidad bajo control.

torch.nn.La longitud del archivo del módulo depende de la versión de PyTorch. No es cada vez más sencillo.

No subestime el tiempo y los recursos necesarios para mantener un gran código de investigación compartido. Cuanto más se utiliza una biblioteca de investigación, más complicada se vuelve. Sucede más rápido que en una biblioteca típica porque cada dirección de investigación tiene un caso de uso ligeramente diferente. Establezca reglas muy estrictas sobre lo que se puede aportar. De lo contrario, el código compartido se vuelve frágil y cubierto de una gran cantidad de opciones, optimizaciones con errores y casos extremos. Dado que la mayor parte del código de investigación desaparece, toda esta complejidad adicional nunca se volverá a utilizar. Eliminar parte de su código compartido le permitirá tener algo de tiempo para realizar una investigación real.

Diseño para exploración, no para reutilización de código

Es cierto que no desea preparar demasiado su código para el futuro, ni siquiera en producción. Intente implementar la solución más simple posible que cumpla con los requisitos. Pero en el código de producción siempre hay aspectos de mantenibilidad a considerar. Por ejemplo, el manejo de errores, la velocidad, el registro y la modularización es en lo que normalmente hay que pensar.


En el código de investigación, nada de eso importa. Sólo desea demostrar rápidamente que una idea es buena o mala de la manera más rápida posible y seguir adelante. Entonces, ¡la sucia simplicidad que lo logra sin ningún módulo o API está totalmente bien!


No pierda tiempo valioso en inversiones prematuras en software como:

  • crear interfaces de componentes demasiado pronto en el proyecto. Pasarás demasiado tiempo adaptándote a limitaciones artificiales creadas por ti mismo.
  • Optimizar la infraestructura de capacitación en aprendizaje profundo antes de comprometerse con una solución de aprendizaje profundo.
  • utilizando configuraciones de producción/fábricas/sistemas de serialización o clases base. Muy a menudo no necesitas su funcionalidad durante la creación de prototipos.
  • sistemas de verificación de tipo y pelusa demasiado estrictos. No hay razón para frenar el código de investigación desechable y que cambia rápidamente.

2. Invierta en exploración rápida

El objetivo de un proyecto de investigación es encontrar una solución novedosa. Nadie sabe (por definición) cómo es. Es similar a un proceso de optimización en un panorama de investigación complicado con información limitada. Para encontrar un buen mínimo, es necesario probar muchos caminos, reconocer los buenos y malos caminos y no quedarse estancado en los mínimos locales. Para hacerlo todo rápido, a veces es necesario realizar inversiones en software en lugar de endeudarse en tecnología.

Acelerar caminos comunes

Invierta en acelerar partes comunes de sus proyectos de investigación.

Hay varios caminos de investigación diferentes que desea probar. ¿Existe un diseño, una biblioteca o una optimización que reduciría el tiempo de la mayoría de los caminos? Debe tener cuidado de no diseñar demasiado nada porque no siempre conoce todas las ideas que está a punto de probar. Esto es muy personalizado para cada proyecto, pero aquí hay algunos ejemplos:


  • Si capacita redes profundas, invierta en infraestructura de capacitación. Descubra los hiperparámetros que le permitirán converger durante el entrenamiento de forma rápida y fiable
  • Si cada experimento requiere que uses un modelo diferente, descubre cómo puedes intercambiarlos rápidamente (por ejemplo, usando un sistema de fábrica simple o simplemente copiando y pegando).
  • Si cada experimento tiene demasiados parámetros y es difícil de gestionar, invierta en una buena biblioteca de configuración.

Ampliarse rápidamente

Invertir en velocidad para iniciar nuevas vías de investigación. Necesita muchas direcciones diversas para encontrar la solución.

Los investigadores deberían poder iniciar nuevas ideas diversas rápidamente. Parece fácil al inicio del proyecto. Pero luego, gradualmente, se vuelve cada vez más difícil a medida que las personas se afianzan en sus caminos de investigación favoritos. Para abordar esto, los cambios culturales y organizativos son esenciales. Debería haber un proceso que detenga las investigaciones no prometedoras antes de invertir demasiado dinero y emociones en ellas. Los días de demostración periódicos y las revisiones técnicas por pares pueden servir como estrategias efectivas para este propósito. También es importante encontrar un equilibrio entre las personas que se lanzan a una nueva idea brillante y cierran adecuadamente los proyectos actuales.


Pero esta es una publicación de software, así que aquí hay algunas prácticas para facilitar la ramificación de nuevos proyectos:

  • mantener el código de evaluación separado de los algoritmos. Las evaluaciones suelen ser más estables que las direcciones de investigación.
  • acepte comenzar un nuevo proyecto desde cero, pero luego tenga cuidado con los componentes que se reutilizan. Modularizarlos y limpiarlos es una buena inversión.
  • En un nuevo proyecto de investigación, implementar primero el componente más innovador y arriesgado. Al hacerlo, se identifican la mayoría de los obstáculos que guiarán el diseño de software futuro.

Aumentar la relación señal-ruido

Los errores y el no determinismo pueden descarrilar los proyectos de investigación y hacer que los resultados no sean concluyentes

El código ruidoso y con errores hace que los resultados sean tan ambiguos y poco concluyentes que todo el proyecto será una pérdida de tiempo. Si bien no debes diseñar demasiadas cosas, puedes seguir fácilmente estas simples reglas generales para evitar código desordenado:


  • Evite el código con efectos secundarios.

  • por defecto a funciones en lugar de clases; y con las clases, prefiera la encapsulación frente a la herencia

  • minimizar la longitud de funciones/clases/módulos; minimizar el número de declaraciones if

  • Conozco bien Python, pero uso técnicas simples. Resista la tentación de adentrarse en la maleza intelectual de las metaclases, los decoradores y la programación funcional.


Es complicado trabajar con un software que produce diferentes resultados durante diferentes ejecuciones. Si tomaste una decisión importante pero equivocada basándose en una semilla desafortunada, vas a perder mucho tiempo recuperándote. A continuación se ofrecen algunos consejos cuando se trata de software no determinista:


  • comprender si el ruido proviene del algoritmo o de su evaluación. Las fuentes de ruido se agravan y usted debe esforzarse por lograr una evaluación completamente determinista.
  • No dejes de buscar fuentes de aleatoriedad hasta que realmente obtengas un guión reproducible. Recuerde que después de encontrar todas las semillas aleatorias, el ruido puede provenir de datos o de funciones genéricas con efectos secundarios.
  • varíe las semillas y determine la variación inicial de sus resultados. No tome decisiones sobre resultados que no sean estadísticamente significativos.

Conclusión

El remate proviene de esta publicación sobre el código de investigación:


“No te preocupas por [un buen diseño de software] porque el código no es el punto. El código es una herramienta que te brinda la respuesta que necesitas” .


Es extremadamente importante tener buenas bases de codificación. Pero al final del día, lo que importa es la exploración y el producto realmente útil. Si utiliza demasiado software de producción en la investigación, perderá el tiempo necesario para descubrir algo nuevo. En su lugar, encuentre lo que ralentiza su proceso de exploración. Acelere las rutas de investigación invirtiendo en ramificaciones rápidas, tiempo para obtener resultados y código limpio y silencioso.


Sería una locura argumentar completamente en contra de la reutilización de código. Sólo quiero señalar que la reutilización de código debe ser una actividad bien equilibrada. En la investigación, la proporción de código desechable es mayor que en la producción. La balanza se inclina aún más en contra de la reutilización. Aquí hay algunas publicaciones más excelentes con los inconvenientes de la reutilización de código:


Y aquí hay algunas publicaciones más que abogan por las prácticas de copypasting:

¡Gracias por leer! Siento que algunas partes son un poco controvertidas, ¡házmelo saber en los comentarios!


También aparece aquí .