# Software 2.0

El Software 2.0 es un término acuñado por Andrej Karpathy en 2017 en contraposición al desarrollo de software tradicional que sería el Software 1.0. El «stack» clásico del Software 1.0 está escrito en lenguajes como Python o C++. Se compone de instrucciones explícitas a la computadora escritas por un programador. Al escribir cada línea de código, el programador identifica un punto específico en el espacio de programa con algún comportamiento deseable. Por el contrario, el Software 2.0 está escrito en un lenguaje mucho más abstracto y hostil a los humanos, como los pesos de una red neuronal. Ningún ser humano está involucrado en la escritura de este código porque hay muchos pesos (las redes típicas pueden tener millones), y codificar directamente en pesos es algo difícil. En cambio, en el Software 2.0 el enfoque es especificar algún objetivo sobre el comportamiento de un programa deseable (por ejemplo, «satisfacer un conjunto de datos de pares de entrada y salida de ejemplos», o «ganar un juego de Go»), escribir un esqueleto aproximado del código (es decir, una arquitectura de red neuronal) que identifica un subconjunto del espacio de programa para buscar y utilizar los recursos computacionales a nuestra disposición para buscar en este espacio un programa que funcione. En el caso de las redes neuronales, se restringe la búsqueda a un subconjunto continuo del espacio de programa donde el proceso de búsqueda se puede hacer eficiente con retropropagación y descenso de gradiente estocástico.
En Software 1.0, el código fuente diseñado por humanos (por ejemplo, algunos archivos «.cpp») se compila en un binario que hace un trabajo útil. En Software 2.0, la mayoría de las veces el código fuente comprende 1) el conjunto de datos que define el comportamiento deseable y 2) la arquitectura de la red neuronal que proporciona el esqueleto aproximado del código, pero con muchos detalles (los pesos) para completar. El proceso de entrenamiento de la red neuronal compila el conjunto de datos en el binario, la red neuronal final. En la mayoría de las aplicaciones prácticas de hoy, las arquitecturas de redes neuronales y los sistemas de entrenamiento están cada vez más estandarizados en un producto, por lo que la mayor parte del «desarrollo de software» activo toma la forma de curar, crecer, masajear y limpiar conjuntos de datos etiquetados.

## Introducción

Software 1.0: Los ingenieros formalmente especifican sus problemas, diseñan algoritmos cuidadosamente, componen sistemas y subsistemas o dividen sistemas complejos en componentes más pequeños.
Software 2.0: Los ingenieros recopilan datos de entrenamiento con los que alimentan un algoritmo ML (Machine Learning: Aprendizaje automático) que sintetizará una aproximación de la función definida por ese conjunto de datos de entrenamiento. En lugar de que el interés esté en el código de programación, en el Software 2.0 todo se centra en los datos y la compilación de código fuente queda reemplazada por los modelos de entrenamiento con datos.
Además de las funciones que sintetizan los algoritmos ML, el Software 2.0 incluye con frecuencia muchas otras funciones que los programadores implementan usando el paradigma Software 1.0.
Desde la década de 2010, los avances tanto en los algoritmos de aprendizaje automático como en el hardware de la computadora han llevado a métodos más eficientes para entrenar redes neuronales profundas que contienen muchas capas de unidades ocultas no lineales y una capa de salida muy grande. Para 2019, las unidades de procesamiento gráfico (GPU), a menudo con mejoras específicas de IA, habían desplazado a las CPU como el método dominante para entrenar la IA en la nube comercial a gran escala.
En 2018 OpenAI estimó el cálculo computacional utilizado en los proyectos de aprendizaje profundo desde AlexNet (2012) a AlphaZero (2017), y encontró un aumento de 300 000 veces en la cantidad de cálculo requerido. La línea de tendencia exponencial indicaba que cada 3.4 meses se duplicaba la potencia de cálculo usada para los mayores proyectos de inteligencia artificial.

## Flujo de trabajo ML
### Orientado a datos

* Requerimientos del modelo (model requirements): Identificar los modelos ML apropiados y las características adecuadas.
* Recopilación de datos (data collection): Conseguir conjuntos de datos de lugares existentes o generar nuevos conjuntos de datos.
* Limpieza de datos (data cleaning): Retirar registros imprecisos o que generen ruido en el conjunto de datos.
* Etiquetado de datos (data labeling): Asignar etiquetas de verdad a cada registro.
* Ingeniería de características (feature engineering): Identificar las características informativas de un conjunto de datos para el modelo.

### Orientado al modelo

* Entrenamiento del modelo (model training): Identificar el modelo y entrenarlo con el conjunto de datos etiquetado.
* Evaluación del modelo (model evaluation): Evaluar el modelo de entrenamiento.
* Implementación del modelo (model deployment): Implementar el modelo en una solución de software.
* Monitoreo del modelo (model monitoring): Monitorear el modelo para detectar posibles errores.

## Componentes

De forma similar a cómo la disponibilidad de un rico ecosistema de librerías reutilizables contribuyó a grandes ganancias de productividad en el Software 1.0, la disponibilidad de librerías como TensorFlow, Scikit-Learn y Keras es un componente clave para el crecimiento del Software 2.0.
Empresas como Google, Facebook, Microsoft y Amazon invierten activamente en librerías ML de código abierto.
La disponibilidad de los últimos algoritmos ML (state-of-the-art) en librerías hace que sea relativamente fácil usar ML en aplicaciones de software partiendo de cero o transformar aplicaciones de Software 1.0 en aplicaciones de Software 2.0.

### Python

Python es la «lengua franca» para ML. Python es un lenguaje de programación de propósito general, de alto nivel e interpretado. Reúne la potencia de un lenguaje de propósito general con la facilidad de uso de los lenguajes de scripting en dominios específicos.

### Librerías ML

ML (Machine Learning: Aprendizaje automatizado) abarca varios tipos de algoritmos de aprendizaje como:
* Aprendizaje supervisado (supervised learning)
* Aprendizaje no supervisado (unsupervised learning)
* Aprendizaje profundo (deep learning)
* Aprendizaje reforzado (reinforcement learning).
Para proporcionar un acceso rápido a estos algoritmos la comunidad de código abierto desarrolló muchas librerías Python ML como:
* Scikit-Learn
* TensorFlow
* Theano
* Caffe
* Keras
* PyTorch
Estas librerías proporcionan algoritmos que permiten que los desarrolladores apliquen fácilmente soluciones basadas en ML a objetivos de negocio. Además de las librerías ML, los desarrolladores frecuentemente usan librerías que proporcionan:
* Computación numérica optimizada: Numpy
* Estructuras de datos eficientes: Pandas
* Visualización: Matplotlib

## Desafíos

El Software 2.0 hereda los desafíos de las librerías ML:
* Dependencia de los datos. Los algoritmos ML infieren reglas que gobiernan el comportamiento de los sistemas desde los datos de entrenamiento y producen modelos ML que sintetizan las reglas aprendidas. La precisión de las decisiones de los modelos ML depende de los datos de entrenamiento.
* Dependencia del modelo pre-entrenado: El Software 2.0 ejecuta modelos ML para tomar decisiones en entornos de producción, por ejemplo, identificar un correo electrónico como spam o no spam.
* Evolución rápida: Los investigadores descubren nuevos algoritmos ML y continúan mejorando los algoritmos ML existentes. Las librerías ML que implementan esos algoritmos cambian rápidamente lanzando nuevas versiones muy frecuentemente.
* Requerimiento para hardware optimizado: Las Librerías ML normalmente requieren hardware optimizado como GPU y TPU para entrenar modelos ML de forma eficiente.

## Limitaciones

* Sesgos y diversidad. Los conjuntos de datos de entrenamiento deben incluir diferentes etnias y entornos culturales.
* Explicación. El Software 2.0 usando ML plantea preguntas en cuanto su razonamiento. Es difícil explicar por qué el software hace lo que hace y es esencial explicarlo.
* Precisión. Un sistema ML puede no ser preciso al 100%, pero puede cometer menos errores que un humano. Los humanos perdonan mejor los errores humanos.

## Tendencia

Un estudio de 2021 afirmó que entre 2013 y 2018 los nuevos proyectos de Software 2.0 en GitHub crecieron del 1.75% al 49.63% del total. ML (Aprendizaje automático) era entonces el campo de mayor crecimiento en las ciencias de la información.
El aumento del Software 2.0 tiene implicaciones para investigadores, fabricantes de herramientas de software, vendedores de librerías ML, vendedores de hardware y desarrolladores de ML.

## Andrej Karpathy

El 11 de noviembre de 2017 Andrej Karpathy publicó un artículo seminal titulado «Software 2.0» en el que afirmaba que las redes neuronales no eran otro clasificador, sino que representaban el principio de un cambio fundamental en la forma en que se desarrollaba software. El stack clásico del Software 1.0 está escrito en lenguajes como Python, C++. Se compone de instrucciones explícitas a la computadora escritas por un programador. Al escribir cada línea de código, el programador identifica un punto específico en el espacio de programa con algún comportamiento deseable. Por el contrario, el Software 2.0 está escrito en un lenguaje mucho más abstracto y hostil a los humanos, como los pesos de una red neuronal. Ningún ser humano está involucrado en la escritura de este código porque hay muchos pesos (las redes típicas pueden tener millones), y codificar directamente en pesos es algo difícil.
En cambio, en el Software 2.0 el enfoque es especificar algún objetivo sobre el comportamiento de un programa deseable (por ejemplo, «satisfacer un conjunto de datos de pares de entrada y salida de ejemplos», o «ganar un juego de Go»), escribir un esqueleto aproximado del código (es decir, una arquitectura de red neuronal) que identifica un subconjunto del espacio de programa para buscar y utilizar los recursos computacionales a nuestra disposición para buscar en este espacio un programa que funcione. En el caso de las redes neuronales, se restringe la búsqueda a un subconjunto continuo del espacio de programa donde el proceso de búsqueda se puede hacer (algo sorprendentemente) eficiente con retropropagación y descenso de gradiente estocástico.
En Software 1.0, el código fuente diseñado por humanos (por ejemplo, algunos archivos «.cpp») se compila en un binario que hace un trabajo útil. En Software 2.0, la mayoría de las veces el código fuente comprende 1) el conjunto de datos que define el comportamiento deseable y 2) la arquitectura de la red neuronal que proporciona el esqueleto aproximado del código, pero con muchos detalles (los pesos) para completar. El proceso de entrenamiento de la red neuronal compila el conjunto de datos en el binario, la red neuronal final. En la mayoría de las aplicaciones prácticas de hoy, las arquitecturas de redes neuronales y los sistemas de entrenamiento están cada vez más estandarizados en un producto, por lo que la mayor parte del «desarrollo de software» activo toma la forma de curar, crecer, masajear y limpiar conjuntos de datos etiquetados. Esto está alterando fundamentalmente el paradigma de programación mediante el cual iteramos en nuestro software, ya que los equipos se dividen en dos: los programadores 2.0 (etiquetadores) editan y amplían los conjuntos de datos, mientras que unos pocos programadores 1.0 mantienen e iteran la infraestructura del código circundante, analíticas, visualizaciones e interfaces de etiquetado. Una gran parte de los problemas del mundo real tienen la propiedad de que es significativamente más fácil recolectar los datos (o más generalmente, identificar un comportamiento deseable) que escribir explícitamente el programa. Debido a esto y a muchos otros beneficios de los programas de Software 2.0, hay una transición masiva en la industria donde una gran cantidad de código 1.0 se está transfiriendo a código 2.0.
Karpathy puso como ejemplos de esa transición:
* El reconocimiento visual solía consistir en funciones diseñadas con un poco de aprendizaje automático al final (por ejemplo, una SVM). Desde entonces, descubrimos características visuales mucho más poderosas al obtener grandes conjuntos de datos (por ejemplo, ImageNet) y buscar en el espacio de las arquitecturas de redes neuronales convolucionales. Más recientemente, ni siquiera confiamos en nosotros mismos para codificar manualmente las arquitecturas y también hemos comenzado a buscarlas.
* El reconocimiento de voz solía involucrar una gran cantidad de preprocesamiento, modelos de mezcla gaussiana y modelos de Markov ocultos, pero hoy en día consiste casi en su totalidad en redes neuronales.
* Históricamente, la síntesis de voz se ha abordado con varios mecanismos de unión, pero hoy en día los modelos más avanzados son ConvNets grandes (por ejemplo, WaveNet ) que producen salidas de señal de audio sin procesar.
* La traducción automática se ha utilizado habitualmente con técnicas estadísticas basadas en frases, pero las redes neuronales se están convirtiendo rápidamente en dominantes. Las arquitecturas preferidas están formadas en entornos multilingües , donde un solo modelo se traduce de cualquier idioma de origen a cualquier idioma de destino, y en entornos poco supervisados (o totalmente no supervisados).
* Juegos. Durante mucho tiempo se habían desarrollado programas de juego Go codificados explícitamente a mano, pero AlphaGo Zero (una ConvNet que observa el estado bruto del tablero y realiza un movimiento) se había convertido, con mucho, en el jugador más fuerte del juego.
* Bases de datos. Los sistemas más tradicionales fuera de la inteligencia artificial también veían indicios tempranos de una transición. Por ejemplo, «The Case for Learned Index Structures» reemplaza los componentes centrales de un sistema de administración de datos con una red neuronal, superando a los B-Trees optimizados para caché en hasta un 70% en velocidad mientras reduce un orden de magnitud en el uso de la memoria.
Karpathy apuntó los beneficios del Software 2.0:
* Computacionalmente homogéneo. Una red neuronal típica está, en primer orden, formada por un sándwich de solo dos operaciones: multiplicación de matrices y umbral en cero (ReLU). Compare eso con el conjunto de instrucciones del software clásico, que es significativamente más heterogéneo y complejo. Debido a que solo tiene que proporcionar la implementación del Software 1.0 para una pequeña cantidad de primitivas computacionales centrales (por ejemplo, multiplicación de matrices), es mucho más fácil hacer varias garantías de corrección/rendimiento.
* Fácil de hornear en silicio. Dado que el conjunto de instrucciones de una red neuronal es relativamente pequeño, es significativamente más fácil implementar estas redes mucho más cerca del silicio, por ejemplo, con ASIC personalizados, chips neuromórficos, etc.
* Tiempo de ejecución constante. Cada iteración de un pase hacia adelante de una red neuronal típica requiere exactamente la misma cantidad de FLOPS. No hay variabilidad basada en las diferentes rutas de ejecución que su código podría tomar a través de una base de código C++ en expansión. Por supuesto, podría tener gráficos de cálculo dinámicos, pero el flujo de ejecución normalmente sigue estando significativamente limitado. De esta manera, también tenemos casi la garantía de que nunca nos encontraremos en bucles infinitos no deseados.
* Uso constante de la memoria. No hay memoria asignada dinámicamente en ningún lugar, por lo que también hay pocas posibilidades de tener que usar la memoria de intercambio (swap) en disco o de tener pérdidas de memoria que haya que buscar en el código.
* Es muy portable. Una secuencia de multiplicaciones de matriz es significativamente más fácil de ejecutar en configuraciones computacionales arbitrarias en comparación con los binarios o scripts clásicos.
* Es muy ágil. Si en un programa C++ alguien quisiera hacerlo dos veces más rápido (a costa del rendimiento si fuera necesario), no sería nada trivial ajustar el sistema para la nueva especificación. Sin embargo, en Software 2.0 se puede tomar la red, eliminar la mitad de los canales, reentrenar y listo, funciona exactamente al doble de velocidad y funciona un poco peor. Por el contrario, si consigue más datos/cálculo, puede hacer que su programa funcione mejor de inmediato con solo agregar más canales y volver a entrenar la red neuronal.
* Los módulos pueden fusionarse en un todo óptimo. Nuestro software a menudo se descompone en módulos que se comunican a través de funciones públicas, API o puntos finales. Sin embargo, si dos módulos de Software 2.0 que se entrenaron originalmente por separado interactúan, podemos propagarlos fácilmente a través del conjunto.
* Es mejor que un humano. En cualquier campo que tenga algo que ver con imágenes/video y sonido/voz, una red neuronal es una pieza de código mejor que cualquier cosa que un humano pueda crear en la mayoría de métricas.

## Aplicaciones

El Software 2.0 ha reinventado dominios como:
* Conducción autónoma.
* Descubrimiento de nuevas drogas.
* Traducción automática.
* Detección de fraudes financieros.
* Detección de malware (software malicioso).
* Herramientas de ingeniería de software.