Cómo puedes entrenar a una IA para convertir tus maquetas de diseño en HTML y CSS

Dentro de tres años, el aprendizaje profundo cambiará el desarrollo del front-end. Aumentará la velocidad de creación de prototipos y reducirá la barrera para la creación de software.

El campo despegó el año pasado cuando Tony Beltramelli presentó el documento pix2code y Airbnb lanzó sketch2code .

Foto de Wesson Wang en Unsplash

Actualmente, la barrera más grande para automatizar el desarrollo de aplicaciones para el usuario es el poder de cómputo. Sin embargo, podemos utilizar algoritmos de aprendizaje profundo actuales, junto con datos de entrenamiento sintetizados, para comenzar a explorar la automatización de front-end artificial en este momento.

En esta publicación, le enseñaremos a una red neuronal cómo codificar un sitio web básico de HTML y CSS basado en una imagen de una maqueta de diseño. Aquí hay una descripción general rápida del proceso:

1) Dar una imagen de diseño a la red neuronal entrenada

2) La red neuronal convierte la imagen en formato HTML

3) Salida renderizada

Construiremos la red neuronal en tres iteraciones.

En primer lugar, haremos una versión mínima básica para entender las partes móviles. La segunda versión, HTML, se enfocará en automatizar todos los pasos y explicar las capas de redes neuronales. En la versión final, Bootstrap, crearemos un modelo que pueda generalizar y explorar la capa LSTM.

Todo el código está preparado en GitHub y FloydHub en cuadernos Jupyter. Todos los portátiles FloydHub están dentro del directorio floydhub y los equivalentes locales están en local .

Los modelos se basan en el documento pix2code de Beltramelli y en los tutoriales de subtítulos de imagen de Jason Brownlee. El código está escrito en Python y Keras, un marco en la parte superior de TensorFlow.

Si eres nuevo en el aprendizaje profundo, te recomiendo que te hagas una idea de las redes neuronales convolucionales y de Python. Mis tres publicaciones anteriores en el blog de FloydHub lo ayudarán a comenzar:

Core Logic

Repasemos nuestro objetivo. Queremos construir una red neuronal que genere un marcado HTML / CSS que corresponda a una captura de pantalla.

Cuando entrenas la red neuronal, le das varias capturas de pantalla con HTML correspondiente.

Aprende prediciendo todas las etiquetas de marcado HTML coincidentes una a una. Cuando predice la siguiente etiqueta de marcado, recibe la captura de pantalla y todas las etiquetas de marcado correctas hasta ese momento.

Aquí hay un ejemplo simple de datos de capacitación en una hoja de Google.

Crear un modelo que prediga palabra por palabra es el enfoque más común en la actualidad. Hay otros enfoques , pero ese es el método que usaremos a lo largo de este tutorial.

Tenga en cuenta que para cada predicción obtiene la misma captura de pantalla. Entonces, si tiene que predecir 20 palabras, obtendrá la misma maqueta de diseño veinte veces. Por ahora, no te preocupes por cómo funciona la red neuronal. Concéntrese en captar la entrada y salida de la red neuronal.

Vamos a centrarnos en el marcado anterior. Supongamos que capacitamos a la red para predecir la frase "Puedo codificar". Cuando recibe "I", entonces predice "puede". La próxima vez recibirá "Yo puedo" y podrá predecir "código". Recibe todas las palabras anteriores y solo tiene que predecir la próxima palabra.

La red neuronal crea funciones a partir de los datos. La red crea funciones para vincular los datos de entrada con los datos de salida. Tiene que crear representaciones para comprender lo que está en cada captura de pantalla, la sintaxis HTML, que ha predicho. Esto construye el conocimiento para predecir la próxima etiqueta.

Cuando quiere usar el modelo entrenado para el uso en el mundo real, es similar a cuando entrena el modelo. El texto se genera uno por uno con la misma captura de pantalla cada vez. En lugar de alimentarlo con las etiquetas HTML correctas, recibe el marcado que ha generado hasta ahora. Luego, predice la siguiente etiqueta de marcado. La predicción se inicia con una "etiqueta de inicio" y se detiene cuando predice una "etiqueta final" o alcanza un límite máximo. Aquí hay otro ejemplo en una hoja de Google .

Versión "Hello World"

Construyamos una versión de "mundo hello". Le proporcionaremos a una red neuronal una captura de pantalla con un sitio web que muestra "Hello World!" Y le enseñaremos a generar el marcado.

Primero, la red neuronal mapea la maqueta de diseño en una lista de valores de píxel. De 0 a 255 en tres canales: rojo, azul y verde.

Para representar el marcado de una manera que la red neuronal entiende, utilizo una codificación en caliente . Por lo tanto, la frase "Puedo codificar" podría mapearse como la siguiente.

En el gráfico de arriba, incluimos la etiqueta de inicio y finalización. Estas etiquetas son señales de cuándo la red comienza sus predicciones y cuándo detenerse.

Para los datos de entrada, usaremos oraciones, comenzando con la primera palabra y luego agregando cada palabra una por una. Los datos de salida son siempre una palabra.

Las oraciones siguen la misma lógica que las palabras. También necesitan la misma longitud de entrada. En lugar de estar limitado por el vocabulario, están limitados por la longitud máxima de la oración. Si es más corto que la longitud máxima, lo llena con palabras vacías, una palabra con solo ceros.

Como puede ver, las palabras se imprimen de derecha a izquierda. Esto obliga a cada palabra a cambiar de posición para cada ronda de entrenamiento. Esto permite que el modelo aprenda la secuencia en lugar de memorizar la posición de cada palabra.

En el siguiente gráfico hay cuatro predicciones. Cada fila es una predicción. A la izquierda están las imágenes representadas en sus tres canales de color: rojo, verde y azul y las palabras anteriores. Fuera de los corchetes están las predicciones una por una, terminando con un cuadrado rojo para marcar el final.

bloques verdes = tokens de inicio | bloque rojo = token final

 # Longitud de la oración más larga 
max_caption_len = 3
# Tamaño del vocabulario
vocab_size = 3
 # Cargar una captura de pantalla para cada palabra y convertirlas en dígitos 
images = []
para mí en el rango (2):
images.append (img_to_array (load_img ('screenshot.jpg', target_size = (224, 224))))
images = np.array (imágenes, dtype = flotar)
# Entrada de preproceso para el modelo VGG16
images = preprocess_input (imágenes)
 #Introducir tokens de inicio en codificación única 
html_input = np.array (
[[[0., 0., 0.], #start
[0., 0., 0.],
[1., 0., 0.]],
[[0., 0., 0.], #start <HTML> ¡Hola mundo! </ HTML>
[1., 0., 0.],
[0., 1., 0.]]])
 # Gira la próxima palabra en una codificación en caliente 
next_words = np.array (
[[0., 1., 0.], # <HTML> ¡Hola mundo! </ HTML>
[0., 0., 1.]]) # final
 # Cargar el modelo VGG16 entrenado en imagenet y generar la característica de clasificación 
VGG = VGG16 (pesos = 'imagenet', include_top = True)
# Extraer las características de la imagen
features = VGG.predict (imágenes)
 # Cargue la función en la red, aplique una capa densa y repita el vector 
vgg_feature = Entrada (forma = (1000,))
vgg_feature_dense = Dense (5) (vgg_feature)
vgg_feature_repeat = RepeatVector (max_caption_len) (vgg_feature_dense)
# Extraer información de la ubicación de entrada
language_input = Entrada (shape = (vocab_size, vocab_size))
language_model = LSTM (5, return_sequences = True) (language_input)
 # Concatenar la información de la imagen y la entrada 
decodificador = concatenar ([vgg_feature_repeat, language_model])
# Extraer información de la salida concatenada
decodificador = LSTM (5, return_sequences = False) (decodificador)
# Predecir qué palabra viene después
decoder_output = Dense (vocab_size, activation = 'softmax') (decodificador)
# Compilar y ejecutar la red neuronal
modelo = Modelo (entradas = [vgg_feature, language_input], outputs = decoder_output)
model.compile (loss = 'categórico_crossentropy', optimizador = 'rmsprop')
 # Entrena la red neuronal 
model.fit ([features, html_input], next_words, batch_size = 2, shuffle = False, epochs = 1000)

En la versión de hello world, usamos tres tokens: start , <HTML><center><H1>Hello World!</H1></center></HTML> y end . Un token puede ser cualquier cosa. Puede ser un personaje, palabra o frase. Las versiones de caracteres requieren un vocabulario más pequeño pero limitan la red neuronal. Los tokens de nivel de palabra tienden a funcionar mejor.

Aquí hacemos la predicción:

 # Create an empty sentence and insert the start token 
sentence = np.zeros((1, 3, 3)) # [[0,0,0], [0,0,0], [0,0,0]]
start_token = [1., 0., 0.] # start
sentence[0][2] = start_token # place start in empty sentence

# Making the first prediction with the start token
second_word = model.predict([np.array([features[1]]), sentence])

# Put the second word in the sentence and make the final prediction
sentence[0][1] = start_token
sentence[0][2] = np.round(second_word)
third_word = model.predict([np.array([features[1]]), sentence])

# Place the start token and our two predictions in the sentence
sentence[0][0] = start_token
sentence[0][1] = np.round(second_word)
sentence[0][2] = np.round(third_word)

# Transform our one-hot predictions into the final tokens
vocabulary = ["start", "<HTML><center><H1>Hello World!</H1></center></HTML>", "end"]
for i in sentence[0]:
print(vocabulary[np.argmax(i)], end=' ')

Salida

  • 10 épocas: start start start
  • 100 épocas: start <HTML><center><H1>Hello World!</H1></center></HTML> <HTML><center><H1>Hello World!</H1></center></HTML>
  • 300 épocas: start <HTML><center><H1>Hello World!</H1></center></HTML> end

Errores que cometí:

  • Cree la primera versión de trabajo antes de recopilar los datos. Al principio de este proyecto, logré obtener una copia de un antiguo archivo del sitio web de alojamiento de Geocities. Tenía 38 millones de sitios web. Cegado por el potencial, ignoré la gran carga de trabajo que se requeriría para reducir el vocabulario de 100K.
  • Lidiar con datos de un terabyte requiere un buen hardware o mucha paciencia. Después de que mi mac se topara con varios problemas, terminé usando un potente servidor remoto. Espere alquilar una plataforma con 8 núcleos de CPU modernos y una conexión a Internet de 1GPS para tener un flujo de trabajo decente.
  • Nada tenía sentido hasta que entendí los datos de entrada y salida. La entrada, X, es una captura de pantalla y las etiquetas de marcado previas. La salida, Y, es la siguiente etiqueta de marcado. Cuando obtuve esto, se hizo más fácil entender todo entre ellos. También se hizo más fácil experimentar con diferentes arquitecturas.
  • Tenga en cuenta los agujeros de conejo. Debido a que este proyecto se cruza con muchos campos de aprendizaje profundo, me quedé atrapado en muchos agujeros de conejo en el camino. Pasé una semana programando RNN desde cero, quedé fascinado con la incrustación de espacios vectoriales y fui seducido por implementaciones exóticas.
  • Las redes de imagen a código son modelos de subtítulos de imagen enmascarados. Incluso cuando aprendí esto, todavía ignoré muchos de los títulos de las imágenes, simplemente porque eran menos geniales. Una vez que obtuve cierta perspectiva, aceleré mi aprendizaje del espacio problemático.

Ejecutando el código en FloydHub

FloydHub es una plataforma de capacitación para el aprendizaje profundo. Los descubrí cuando comencé a aprender en profundidad y los he usado desde entonces para entrenar y administrar mis experimentos de aprendizaje profundo. Puede instalarlo y ejecutar su primer modelo en 10 minutos. Definitivamente es la mejor opción para ejecutar modelos en GPU en la nube.

Si eres nuevo en FloydHub, haz la instalación de 2 minutos o mi recorrido de 5 minutos.

Clonar el repositorio

 git clone https://github.com/emilwallner/Screenshot-to-code-in-Keras.git 

Iniciar sesión e iniciar la herramienta de línea de comandos FloydHub

 cd Screenshot-to-code-in-Keras 
floyd login
floyd init s2c

Ejecutar un cuaderno Jupyter en una máquina GPU de nube FloydHub:

 floyd run --gpu --env tensorflow-1.4 --data emilwallner/datasets/imagetocode/2:data --mode jupyter 

Todos los cuadernos están preparados dentro del directorio de FloydHub. Los equivalentes locales están bajo local. Una vez que se está ejecutando, puede encontrar el primer cuaderno aquí: floydhub / Hello world / hello world.ipynb.

Si desea instrucciones más detalladas y una explicación de las banderas, consulte mi publicación anterior .

Versión HTML

En esta versión, automatizaremos muchos de los pasos del modelo Hello World. Esta sección se enfocará en crear una implementación escalable y las piezas móviles en la red neuronal.

Esta versión no podrá predecir HTML desde sitios web aleatorios, pero sigue siendo una gran configuración para explorar la dinámica del problema.

Visión de conjunto

Si ampliamos los componentes del gráfico anterior, se verá así.

Hay dos secciones principales. Primero, el codificador. Aquí es donde creamos las características de la imagen y las características de marcado previas. Las características son los componentes básicos que crea la red para conectar las maquetas de diseño con el marcado. Al final del codificador, pegamos las características de la imagen a cada palabra en el marcado anterior.

El decodificador toma la función de diseño y marcado combinados y crea una próxima función de etiqueta. Esta característica se ejecuta a través de una red neuronal completamente conectada para predecir la próxima etiqueta.

Diseño de maquetas

Como necesitamos insertar una captura de pantalla para cada palabra, esto se convierte en un cuello de botella cuando se entrena la red ( ejemplo ). En lugar de usar las imágenes, extraemos la información que necesitamos para generar el marcado.

La información está codificada en las características de la imagen. Esto se hace mediante el uso de una red neuronal convolucional ya entrenada (CNN). El modelo está pre-entrenado en Imagenet.

Extraemos las características de la capa antes de la clasificación final.

Terminamos con 1536 imágenes de ocho por ocho píxeles conocidas como características. Aunque son difíciles de entender para nosotros, una red neuronal puede extraer los objetos y la posición de los elementos de estas características.

Funciones de marcado

En la versión hello world, usamos una codificación única para representar el marcado. En esta versión, usaremos una palabra incrustada para la entrada y mantendremos la codificación única para la salida.

La forma en que estructuramos cada oración permanece igual, pero cambiamos la forma en que correlacionamos cada ficha. La codificación One-hot trata cada palabra como una unidad aislada. En cambio, convertimos cada palabra en los datos de entrada en listas de dígitos. Estos representan la relación entre las etiquetas de marcado.

La dimensión de esta palabra incrustada es ocho, pero a menudo varía entre 50 y 500 dependiendo del tamaño del vocabulario.

Los ocho dígitos para cada palabra son pesos similares a una red neuronal vainilla. Están sintonizados para mapear cómo se relacionan las palabras entre sí ( Mikolov et al., 2013 ).

Así es como comenzamos a desarrollar funciones de marcado. Las características son lo que desarrolla la red neuronal para vincular los datos de entrada con los datos de salida. Por ahora, no te preocupes por lo que son, profundizaremos en esto en la siguiente sección.

El codificador

Tomaremos las incrustaciones de palabras y las ejecutaremos a través de un LSTM y devolveremos una secuencia de características de marcado. Estos se ejecutan a través de una capa densa distribuida en el tiempo; piense en ella como una capa densa con múltiples entradas y salidas.

Paralelamente, las características de la imagen primero se aplanan. Independientemente de cómo se estructuraron los dígitos, se transforman en una gran lista de números. Luego aplicamos una capa densa en esta capa para formar una característica de alto nivel. Estas características de imagen luego se concatenan a las características de marcado.

Esto puede ser difícil de entender, así que analicémoslo.

Funciones de marcado

Aquí ejecutamos la palabra incrustaciones a través de la capa LSTM. En este gráfico, todas las oraciones están acolchadas para alcanzar el tamaño máximo de tres tokens.

Para mezclar señales y encontrar patrones de nivel superior, aplicamos una capa densa distribuida en el tiempo a las características de marcado. TimeDistributed denso es lo mismo que una capa densa, pero con múltiples entradas y salidas.

Características de la imagen

En paralelo, preparamos las imágenes. Tomamos todas las características de la mini imagen y las transformamos en una larga lista. La información no se cambia, solo se reorganiza.

Nuevamente, para mezclar señales y extraer nociones de nivel más alto, aplicamos una capa densa. Como solo estamos tratando con un valor de entrada, podemos usar una capa densa normal. Para conectar las características de la imagen a las características de marcado, copiamos las características de la imagen.

En este caso, tenemos tres características de marcado. Por lo tanto, terminamos con una cantidad igual de características de imagen y marcado.

Concatenar las características de imagen y marcado

Todas las oraciones están acolchadas para crear tres características de marcado. Ya que hemos preparado las características de la imagen, ahora podemos agregar una función de imagen para cada característica de marcado.

Después de pegar una característica de imagen a cada característica de marcado, terminamos con tres características de marcado de imagen. Esta es la entrada que introducimos en el decodificador.

El decodificador

Aquí usamos las funciones combinadas de marcado de imagen para predecir la próxima etiqueta.

En el siguiente ejemplo, utilizamos tres pares de características de marcado de imagen y emitimos una función de etiqueta siguiente.

Tenga en cuenta que la capa LSTM tiene la secuencia establecida en falso. En lugar de devolver la longitud de la secuencia de entrada, solo predice una característica. En nuestro caso, es una función para la próxima etiqueta. Contiene la información para la predicción final.

La predicción final

Si no puede ver nada al hacer clic en estos enlaces, puede hacer clic con el botón derecho y hacer clic en "Ver origen de página". Aquí está el sitio web original para referencia.

Errores que cometí:

  • Las LSTM son mucho más pesadas para mi cognición en comparación con las CNN . Cuando desenrollé todos los LSTM, se volvieron más fáciles de entender. El video de Fast.ai sobre RNNs fue súper útil. Además, concéntrese en las funciones de entrada y salida antes de intentar comprender cómo funcionan.
  • Construir un vocabulario desde cero es mucho más fácil que reducir un vocabulario enorme. Esto incluye todo, desde fuentes, tamaños div y colores hexadecimales hasta nombres de variables y palabras normales.
  • La mayoría de las bibliotecas se crean para analizar documentos de texto y no codificar. En los documentos, todo está separado por un espacio, pero en el código, necesita un análisis personalizado.
  • Puede extraer características con un modelo que está capacitado en Imagenet. Esto puede parecer contradictorio ya que Imagenet tiene pocas imágenes web. Sin embargo, la pérdida es un 30% más alta en comparación con un modelo pix2code, que está entrenado desde cero. Sería interesante utilizar un modelo de modelo de inicio de sesión previo al tren basado en capturas de pantalla de la web.

Versión Bootstrap

En nuestra versión final, usaremos un conjunto de datos de sitios web bootstrap generados a partir del papel pix2code. Al utilizar el bootstrap de Twitter, podemos combinar HTML y CSS y disminuir el tamaño del vocabulario.

Lo habilitaremos para generar el marcado para una captura de pantalla que no haya visto antes. También profundizaremos en cómo genera conocimiento sobre la captura de pantalla y el marcado.

En lugar de entrenarlo en el marcado de bootstrap, usaremos 17 tokens simplificados que luego traduciremos a HTML y CSS. El conjunto de datos incluye 1500 capturas de pantalla de prueba y 250 imágenes de validación. Para cada captura de pantalla hay un promedio de 65 tokens, lo que da como resultado 96925 ejemplos de entrenamiento.

Al ajustar el modelo en el papel pix2code, el modelo puede predecir los componentes web con un 97% de precisión (BLEU 4-ngram greedy search, más sobre esto más adelante).

Un enfoque de punta a punta

La extracción de características de modelos pre-entrenados funciona bien en modelos de subtítulos de imágenes. Pero después de algunos experimentos, me di cuenta de que el enfoque extremo a extremo de pix2code funciona mejor para este problema. Los modelos pre-entrenados no han sido entrenados en datos web y están personalizados para su clasificación.

En este modelo, reemplazamos las características de imagen pre-entrenadas con una red neuronal convolucional ligera. En lugar de utilizar la combinación máxima para aumentar la densidad de la información, aumentamos los avances. Esto mantiene la posición y el color de los elementos frontales.

Hay dos modelos básicos que lo habilitan: redes neuronales convolucionales (CNN) y redes neuronales recurrentes (RNN). La red neuronal recurrente más común es la memoria a corto y largo plazo (LSTM), por eso es a lo que me referiré.

Hay muchos excelentes tutoriales de CNN, y los cubrí en mi artículo anterior . Aquí, me centraré en los LSTM.

Comprender pasos a tiempo en LSTM

Una de las cosas más difíciles de entender sobre los LSTM es los pasos del tiempo. Una red neuronal de vainilla se puede considerar como dos pasos de tiempo. Si le das "Hola", predice "Mundo". Pero sería difícil predecir más pasos a tiempo. En el siguiente ejemplo, la entrada tiene cuatro pasos, uno para cada palabra.

Los LSTM están hechos para entrada con timespasps. Es una red neuronal personalizada para información en orden. Si desenrolla nuestro modelo, se verá así. Para cada paso hacia abajo, mantienes los mismos pesos. Aplica un conjunto de pesos a la salida anterior y otro conjunto a la nueva entrada.

La entrada y salida ponderadas se concatenan y se suman junto con una activación. Este es el resultado para ese lapso de tiempo. Como reutilizamos los pesos, extraen información de varias entradas y generan conocimiento de la secuencia.

Aquí hay una versión simplificada del proceso para cada paso de tiempo en un LSTM.

Para tener una idea de esta lógica, recomiendo construir un RNN desde cero con el brillante tutorial de Andrew Trask.

Comprender las unidades en capas LSTM

La cantidad de unidades en cada capa de LSTM determina su capacidad para memorizar. Esto también corresponde al tamaño de cada característica de salida. Una vez más, una función es una larga lista de números utilizados para transferir información entre capas.

Cada unidad en la capa LSTM aprende a realizar un seguimiento de diferentes aspectos de la sintaxis. A continuación se muestra una visualización de una unidad que mantiene pistas de la información en la fila div. Este es el marcado simplificado que estamos utilizando para entrenar el modelo de arranque.

Cada unidad LSTM mantiene un estado de celda. Piensa en el estado celular como memoria. Los pesos y las activaciones se utilizan para modificar el estado de diferentes maneras. Esto permite a las capas LSTM ajustar con precisión qué información conservar y descartar para cada entrada.

Es complicado encontrar una manera justa de medir la precisión. Digamos que se compara palabra por palabra. Si su predicción es una palabra fuera de sincronización, es posible que tenga un 0% de precisión. Si elimina una palabra que sincroniza la predicción, puede terminar con 99/100.

Utilicé el puntaje BLEU, la mejor práctica en modelos de traducción de máquina y subtítulos de imagen. Rompe la oración en cuatro n-gramas, de secuencias de 1-4 palabras. En la predicción siguiente, "gato" se supone que es "código".

Para obtener el puntaje final, multiplicas cada puntaje con un 25%, (4/5) * 0.25 + (2/4) * 0.25 + (1/3) * 0.25 + (0/2) * 0.25 = 0.2 + 0.125 + 0.083 + 0 = 0.408. La suma se multiplica con una penalización de longitud de frase. Dado que la longitud es correcta en nuestro ejemplo, se convierte en nuestro puntaje final.

Puede aumentar la cantidad de n-gramas para hacerlo más difícil. Un modelo de cuatro n-gramas es el modelo que mejor se corresponde con las traducciones humanas. Recomiendo ejecutar algunos ejemplos con el siguiente código y leer la página wiki.

 #Crear una función para leer un archivo y devolver su contenido 
def load_doc (nombre de archivo):
file = open (nombre de archivo, 'r')
text = file.read ()
file.close ()
devolver el texto
 def load_data (data_dir): 
text = []
images = []
files_in_folder = os.listdir (data_dir)
files_in_folder.sort ()
para el nombre del archivo en tqdm (files_in_folder):
# Agregar una imagen
if nombre de archivo [-3:] == "npz":
image = np.load (data_dir + nombre de archivo)
images.append (image ['features'])
más:
# Agregar texto y envolverlo en una etiqueta de inicio y fin
sintaxis = '<START>' + load_doc (data_dir + filename) + '<END>'
#Seperate cada palabra con un espacio
sintaxis = '' .join (sintaxis.split ())
#Añadir un espacio entre cada coma
sintaxis = sintaxis.replace (',', ',')
text.append (sintaxis)
images = np.array (imágenes, dtype = flotar)
devolver imágenes, texto
 #Italizar la función para crear el vocabulario 
tokenizer = Tokenizer (filters = '', split = "", lower = False)
#Cree el vocabulario en un orden específico
tokenizer.fit_on_texts ([load_doc ('bootstrap.vocab')])
 dir_name = '../../../../eval/' 
train_features, texts = load_data (dir_name)
 #carga modelo y pesos 
json_file = abrir ('../../../../ model.json', 'r')
loaded_model_json = json_file.read ()
json_file.close ()
loaded_model = model_from_json (loaded_model_json)
# cargar pesos en el nuevo modelo
loaded_model.load_weights ("../../../../pesos.hdf5")
print ("Modelo cargado desde el disco")
 # mapear un entero a una palabra 
def word_for_id (integer, tokenizer):
por palabra, índice en tokenizer.word_index.items ():
if index == entero:
palabra de retorno
devolver ninguno
imprimir (word_for_id (17, tokenizer))
 # generar una descripción para una imagen 
def generate_desc (model, tokenizer, photo, max_length):
photo = np.array ([foto])
# sembrar el proceso de generación
in_text = '<START>'
# iterar sobre toda la longitud de la secuencia
print (' nPredicción ----> n n <START>', end = '')
para mí en el rango (150):
# integer codificar la secuencia de entrada
sequence = tokenizer.texts_to_sequences ([in_text]) [0]
# entrada pad
sequence = pad_sequences ([secuencia], maxlen = max_length)
# predecir la siguiente palabra
yhat = loaded_model.predict ([foto, secuencia], verbose = 0)
# probabilidad de conversión a entero
yhat = argmax (yhat)
# mapa entero a palabra
word = word_for_id (yhat, tokenizer)
# detener si no podemos mapear la palabra
si la palabra es None:
descanso
# agregar como entrada para generar la siguiente palabra
in_text + = palabra + ''
# detener si predecimos el final de la secuencia
imprimir (palabra + '', final = '')
if palabra == '<END>':
descanso
return in_text
 max_length = 48 
 # evaluar la habilidad del modelo 
def evalúa_modelo (modelo, descripciones, fotos, tokenizer, max_length):
real, predicted = list (), list ()
# paso sobre todo el conjunto
para mí en el rango (len (textos)):
yhat = generate_desc (modelo, tokenizer, fotos [i], max_length)
# tienda real y predicho
print (' n nReal ----> n n' + textos [i])
actual.append ([textos [i] .split ()])
predicted.append (yhat.split ())
# calcular puntaje BLEU
bleu = corpus_bleu (real, predicho)
return bleu, real, predicho
 bleu, real, predicho = modelo_de_evaluación (modelo_cargado, textos, características_del_ tren, tokenizador, longitud_máx) 
 #Compilar los tokens en HTML y CSS 
dsl_path = "compilador / assets / web-dsl-mapping.json"
compilador = compilador (dsl_path)
compiled_website = compiler.compile (pronosticado [0], 'index.html')
 imprimir (sitio web compilado) 
imprimir (bleu)

Salida

Enlaces a la salida de muestra

Errores que cometí:

  • Comprenda la debilidad de los modelos en lugar de probar modelos aleatorios. Primero, apliqué elementos aleatorios como la normalización de lotes y las redes bidireccionales e intenté implementar la atención. Después de ver los datos de prueba y ver que no podía predecir el color y la posición con gran precisión, me di cuenta de que había una debilidad en la CNN. Esto me llevó a reemplazar maxpooling con mayores avances. La pérdida de validación pasó de 0,12 a 0,02 y aumentó la puntuación BLEU de 85% a 97%.
  • Solo use modelos pre-entrenados si son relevantes. Dado el pequeño conjunto de datos, pensé que un modelo de imagen preentrenado mejoraría el rendimiento. Según mis experimentos, el modelo de extremo a extremo es más lento de entrenar y requiere más memoria, pero es un 30% más preciso.
  • Planifique una ligera variación cuando ejecute su modelo en un servidor remoto. En mi Mac, lee los archivos en orden alfabético. Sin embargo, en el servidor, fue ubicado al azar. Esto creó una falta de coincidencia entre las capturas de pantalla y el código. Todavía convergía, pero los datos de validación eran un 50% peores que cuando lo arreglé.
  • Asegúrese de comprender las funciones de la biblioteca. Incluya espacio para el token vacío en su vocabulario. Cuando no lo agregué, no incluía uno de los tokens. Solo lo noté después de mirar el resultado final varias veces y darme cuenta de que nunca predijo un token "único". Después de un control rápido, me di cuenta de que ni siquiera estaba en el vocabulario. Además, use el mismo orden en el vocabulario para entrenamiento y pruebas.
  • Use modelos más ligeros cuando experimente. El uso de GRU en lugar de LSTM redujo cada ciclo de época en un 30% y no tuvo un gran efecto en el rendimiento.

Próximos pasos

El desarrollo de front-end es un espacio ideal para aplicar el aprendizaje profundo. Es fácil generar datos, y los algoritmos actuales de aprendizaje profundo pueden mapear la mayor parte de la lógica.

Una de las áreas más interesantes es aplicar atención a LSTM . Esto no solo mejorará la precisión, sino que nos permitirá visualizar dónde pone su foco la CNN a medida que genera el marcado.

La atención también es clave para la comunicación entre el marcado, las hojas de estilo, los scripts y, finalmente, el back-end. Las capas de atención pueden realizar un seguimiento de las variables, lo que permite que la red se comunique entre los lenguajes de programación.

Pero en la característica más cercana, el mayor impacto vendrá de la construcción de una forma escalable de sintetizar datos. Luego puede agregar fuentes, colores, palabras y animaciones paso a paso.

Hasta ahora, la mayor parte del progreso está sucediendo al tomar bocetos y convertirlos en aplicaciones de plantilla. En menos de dos años, podremos dibujar una aplicación en papel y tener el front-end correspondiente en menos de un segundo. Ya hay dos prototipos de trabajo construidos por el equipo de diseño de Airbnb y Uizard .

Aquí hay algunos experimentos para comenzar.

Experimentos

Empezando

  • Ejecuta todos los modelos
  • Prueba diferentes hiperparámetros
  • Pruebe una arquitectura CNN diferente
  • Agregar modelos bidireccionales LSTM
  • Implemente el modelo con un conjunto de datos diferente . (Puede montar fácilmente este conjunto de datos en sus trabajos de FloydHub con este indicador --data emilwallner/datasets/100k-html:data )

Experimentos adicionales

  • Crear una aplicación aleatoria sólida / generador web con la sintaxis correspondiente.
  • Datos para un boceto al modelo de la aplicación. Convierta automáticamente las capturas de pantalla de la aplicación / web en bocetos y use una GAN para crear variedad.
  • Aplique una capa de atención para visualizar el enfoque en la imagen para cada predicción, similar a este modelo .
  • Crea un marco para un enfoque modular. Digamos que tiene modelos de codificador para fuentes, uno para el color, otro para el diseño y los combina con un decodificador. Un buen comienzo podrían ser las características de imagen sólida.
  • Alimente la red con componentes HTML simples y enséñele a generar animaciones usando CSS. Sería fascinante tener un enfoque de atención y visualizar el enfoque en ambas fuentes de entrada.

Muchísimas gracias a Tony Beltramelli y Jon Gold por sus investigaciones e ideas, y por responder preguntas. Gracias a Jason Brownlee por sus estelares tutoriales de Keras (incluí algunos fragmentos de su tutorial en la implementación central de Keras), y a Beltramelli por proporcionar los datos. También gracias a Qingping Hou, Charlie Harrington, Sai Soundararaj, Jannes Klaas, Claudio Cabral, Alain Demenet y Dylan Djian por leer borradores de esto.

Acerca de Emil Wallner

Esta es la cuarta parte de una serie de blogs de varias partes de Emil, mientras aprende profundo aprendizaje. Emil ha pasado una década explorando el aprendizaje humano. Trabajó para la escuela de negocios de Oxford, invirtió en nuevas empresas de educación y creó un negocio de tecnología educativa. El año pasado, se inscribió en Ecole 42 para aplicar su conocimiento del aprendizaje humano al aprendizaje automático.

Si construyes algo o te quedas atascado, hazme un ping a continuación o en twitter: emilwallner . Me encantaría ver lo que estás construyendo.

Esto se publicó primero como una publicación de la comunidad en el blog de Floydhub .