Como treinar um Inteligência Artificial para converter seus modelos de design em HTML e CSS

Dentro de três anos, o aprendizado profundo mudará o desenvolvimento de front-end. Isso aumentará a velocidade de prototipagem e diminuirá a barreira para o software de construção.

O campo decolou no ano passado quando Tony Beltramelli apresentou o papel pix2code e o Airbnb lançou o sketch2code .

Atualmente, a maior barreira para automatizar o desenvolvimento de front-end é o poder de computação. No entanto, podemos usar algoritmos de aprendizado profundo atuais, juntamente com dados de treinamento sintetizados, para começar a explorar a automação artificial de front-end agora.

Nesta publicação, vamos ensinar uma rede neural como codificar um site básico de HTML e CSS baseado em uma imagem de uma maquete de projeto. Aqui está uma visão geral do processo:

1) Dê uma imagem de design à rede neural treinada

2) A rede neural converte a imagem em marcação HTML

3) Produção renderizada

Vamos construir a rede neural em três iterações.

Em primeiro lugar, faremos uma versão mínima para obter uma queda das partes móveis. A segunda versão, HTML, se concentrará na automação de todas as etapas e na explicação das camadas da rede neural. Na versão final, Bootstrap, criaremos um modelo que pode generalizar e explorar a camada LSTM.

Todo o código está preparado no Github e FloydHub nos cadernos Jupyter. Todos os notebooks FloydHub estão dentro do diretório floydhub e os equivalentes locais estão no local .

Os modelos são baseados no papel de pix2code da Beltramelli e nos tutoriais de legendas de imagem de Jason Brownlee. O código está escrito em Python e Keras, uma estrutura em cima do TensorFlow.

Se você é novo no aprendizado profundo, eu recomendaria ter uma idéia das redes neurais de Python, backpropagation e convolution. Minhas três publicações anteriores no blog do FloydHub irão começar:

Lógica do núcleo

Vamos recapitular nosso objetivo. Queremos construir uma rede neural que gerará marcação HTML / CSS que corresponda a uma captura de tela.

Quando você treina a rede neural, você dá várias capturas de tela com HTML correspondente.

Aprende por prever todas as tags de marcação HTML correspondentes, uma a uma. Quando prevê a próxima marca de marcação, ela recebe a captura de tela, bem como todas as marcas de marcação corretas até esse ponto.

Aqui está um exemplo simples de dados de treinamento em uma folha do Google.

A criação de um modelo que prevê palavra por palavra é a abordagem mais comum hoje. Existem outras abordagens , mas esse é o método que usamos ao longo deste tutorial.

Observe que, para cada previsão, ele obtém a mesma captura de tela. Então, se tiver que prever 20 palavras, ele terá a mesma maquiagem de design vinte vezes. Por enquanto, não se preocupe com o funcionamento da rede neural. Concentre-se em agarrar a entrada e saída da rede neural.

Vamos nos concentrar na marcação anterior. Digamos que treinamos a rede para prever a frase “Posso codificar”. Quando recebe “I”, então ele predica “pode”. Na próxima vez, ele receberá “Eu posso” e prever “código”. Recebe todas as palavras anteriores e só tem que prever a próxima palavra.

A rede neural cria recursos dos dados. A rede cria recursos para vincular os dados de entrada com os dados de saída. Ele tem que criar representações para entender o que está em cada captura de tela, a sintaxe HTML, que previu. Isso cria o conhecimento para prever a próxima tag.

Quando você deseja usar o modelo treinado para o uso do mundo real, é semelhante ao de treinar o modelo. O texto é gerado um a um com a mesma captura de tela de cada vez. Em vez de alimentá-lo com as tags HTML corretas, ele recebe a marcação que gerou até agora. Então, ele prevê a próxima marca de marcação. A predição é iniciada com uma “tag de início” e pára quando prevê uma “etiqueta final” ou atinge um limite máximo. Aqui está outro exemplo em uma folha do Google .

Versão “Hello World”

Vamos construir uma versão do “mundo olá”. Vamos alimentar uma rede neural uma captura de tela com um site exibindo “Olá Mundo!” E ensiná-lo a gerar a marcação.

Primeiro, a rede neural mapeia a maquete de projeto em uma lista de valores de pixels. De 0-255 em três canais – vermelho, azul e verde.

Para representar a marcação de uma maneira que a rede neural entenda, eu uso uma codificação quente . Assim, a frase “Eu posso codificar” pode ser mapeada como a abaixo.

No gráfico acima, incluímos a tag de início e término. Essas tags são sugestões para quando a rede inicia suas previsões e quando parar.

Para os dados de entrada, usaremos frases, começando com a primeira palavra e depois adicionando cada palavra uma a uma. Os dados de saída são sempre uma palavra.

Sentenças seguem a mesma lógica que as palavras. Eles também precisam do mesmo comprimento de entrada. Em vez de serem limitados pelo vocabulário, eles são vinculados pelo comprimento máximo da sentença. Se for menor do que o comprimento máximo, preencha com palavras vazias, uma palavra com apenas zeros.

Como você vê, as palavras são impressas da direita para a esquerda. Isso força cada palavra a mudar de posição para cada rodada de treinamento. Isso permite que o modelo aprenda a seqüência em vez de memorizar a posição de cada palavra.

No gráfico abaixo, existem quatro previsões. Cada linha é uma previsão. À esquerda estão as imagens representadas nos seus três canais de cores: vermelho, verde e azul e as palavras anteriores. Fora dos colchetes estão as previsões uma a uma, terminando com um quadrado vermelho para marcar o final.

blocos verdes = tokens iniciais | bloco vermelho = token final

 #Length da sentença mais longa 
 max_caption_len = 3 
 #Size of vocabulary 
 vocab_size = 3
 # Carrega uma captura de tela para cada palavra e converte-os em dígitos 
 imagens = [] 
 para eu no alcance (2): 
 images.append (img_to_array (load_img ('screenshot.jpg', target_size = (224, 224)))) 
 images = np.array (images, dtype = float) 
 # Entrada pré-processada para o modelo VGG16 
 images = preprocess_input (imagens)
 #Turn start tokens em uma codificação de uma só vez 
 html_input = np.array ( 
 [[[0., 0., 0.], #start 
 [0., 0., 0.], 
 [1., 0., 0.]], 
 [[0., 0., 0.], #start <HTML> Olá Mundo! </ HTML> 
 [1., 0., 0.], 
 [0., 1., 0.]]]]
 #Viga a próxima palavra para uma codificação rápida 
 next_words = np.array ( 
 [[0., 1., 0.], # <HTML> Olá Mundo! </ HTML> 
 [0., 0., 1.]]) # fim
 # Carregue o modelo VGG16 treinado em imagenet e publique o recurso de classificação 
 VGG = VGG16 (pesos = 'imagenet', include_top = True) 
 # Extraia os recursos da imagem 
 features = VGG.predict (imagens)
 # Carregue o recurso na rede, aplique uma camada densa e repita o vetor 
 vgg_feature = Entrada (forma = (1000,)) 
 vgg_feature_dense = Dense (5) (vgg_feature) 
 vgg_feature_repeat = RepeatVector (max_caption_len) (vgg_feature_dense) 
 # Extrair informações da seqência de entrada 
 language_input = Input (shape = (vocab_size, vocab_size)) 
 language_model = LSTM (5, return_sequences = True) (language_input)
 # Concatenar as informações da imagem e da entrada 
 decoder = concatenate ([vgg_feature_repeat, language_model]) 
 # Extrair informações da saída concatenada 
 decodificador = LSTM (5, return_sequences = False) (decodificador) 
 # Preditar qual palavra vem a seguir 
 decoder_output = Dense (vocab_size, activation = 'softmax') (decodificador) 
 # Compile e execute a rede neural 
 modelo = Modelo (entradas = [vgg_feature, language_input], outputs = decoder_output) 
 model.compile (loss = 'categorical_crossentropy', otimizador = 'rmsprop')
 # Treinar a rede neural 
 model.fit ([features, html_input], next_words, batch_size = 2, shuffle = False, epochs = 1000)

Na versão mundial do Olá, usamos três tokens: start , <HTML><center><H1>Hello World!</H1></center></HTML> e end . Um token pode ser qualquer coisa. Pode ser um personagem, uma palavra ou uma frase. As versões de caracteres exigem um vocabulário menor, mas restringem a rede neural. Os tokens de nível de palavra tendem a apresentar melhor desempenho.

Aqui fazemos a previsão:

# 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=' ')

Saída

  • 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

Erros que fiz:

  • Crie a primeira versão de trabalho antes de reunir os dados. No início deste projeto, consegui obter uma cópia de um arquivo antigo do site de hospedagem Geocities. Ele tinha 38 milhões de sites. Cegado pelo potencial, ignorei a enorme carga de trabalho que seria necessária para reduzir o vocabulário de tamanho 100K.
  • Lidar com um valor de dados do terabyte requer um bom hardware ou muita paciência. Depois de ter o Mac instalado em vários problemas, acabei usando um poderoso servidor remoto. Espere alugar um equipamento com 8 núcleos de CPU modernos e uma conexão de Internet 1GPS para ter um fluxo de trabalho decente.
  • Nada fez sentido até entender os dados de entrada e saída. A entrada, X, é uma captura de tela e as tags de marcação anteriores. A saída, Y, é a próxima marca de marcação. Quando consegui isso, tornou-se mais fácil entender tudo entre eles. Também se tornou mais fácil experimentar diferentes arquiteturas.
  • Esteja ciente dos buracos de coelho. Como este projeto se cruza com muitos campos em aprendizado profundo, fiquei preso em muitos buracos de coelho ao longo do caminho. Passei uma semana de RNN de programação do raio, fiquei muito fascinado pela incorporação de espaços vetoriais e foi seduzido por implementações exóticas.
  • As redes de imagem para código são modelos de legendas de imagem disfarçadas. Mesmo quando eu aprendi isso, eu ainda ignorei muitos dos artigos de legendas de imagem, simplesmente porque eram menos legais. Depois de ter alguma perspectiva, acelerei minha aprendizagem do espaço do problema.

Executando o código no FloydHub

FloydHub é uma plataforma de treinamento para aprendizagem profunda. Eu me deparei com eles quando eu comecei a aprender aprendizagem profunda e eu usei-os desde então para treinar e gerenciar minhas experiências de aprendizado profundo. Você pode instalá-lo e executar o seu primeiro modelo em 10 minutos. É a melhor opção para executar modelos em GPUs na nuvem.

Se você é novo no FloydHub, faça sua instalação de 2 minutos ou meu passo a passo de 5 minutos.

Clone o repositório

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

Faça o login e inicie a ferramenta de linha de comando FloydHub

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

Execute um notebook Jupyter em uma máquina de GPU de nuvem FloydHub:

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

Todos os cadernos estão preparados dentro do diretório FloydHub. Os equivalentes locais estão sob o local. Uma vez que está em execução, você pode encontrar o primeiro caderno aqui: floydhub / Hello world / hello world.ipynb.

Se você deseja obter instruções mais detalhadas e uma explicação para as bandeiras, verifique minha postagem anterior .

Versão em HTML

Nesta versão, automatizaremos muitas das etapas do modelo Hello World. Esta seção se concentrará na criação de uma implementação escalável e as peças em movimento na rede neural.

Esta versão não será capaz de prever HTML de sites aleatórios, mas ainda é uma ótima configuração para explorar a dinâmica do problema.

Visão geral

Se expandimos os componentes do gráfico anterior, parece assim.

Existem duas seções principais. Primeiro, o codificador. É aqui que criamos recursos de imagem e características de marcação anteriores. Os recursos são os blocos de construção que a rede cria para conectar os modelos de projeto com a marcação. No final do codificador, colamos os recursos da imagem em cada palavra na marcação anterior.

O decodificador leva então o recurso combinado de design e marcação e cria um recurso de tag seguinte. Esse recurso é executado através de uma rede neural totalmente conectada para prever a próxima tag.

Desenhar recursos de mockup

Uma vez que precisamos inserir uma captura de tela para cada palavra, isso se torna um gargalo ao treinar a rede ( exemplo ). Em vez de usar as imagens, extraímos as informações que precisamos para gerar a marcação.

A informação é codificada em recursos de imagem. Isso é feito usando uma rede neural já convocada pré-treinada (CNN). O modelo é pré-treinado na Imagemet.

Extraímos os recursos da camada antes da classificação final.

Acabamos com 1536 imagens de oito por oito pixel conhecidas como características. Embora sejam difíceis de entender para nós, uma rede neural pode extrair os objetos e a posição dos elementos desses recursos.

Características de marcação

Na versão mundial de Olá, usamos uma codificação de um minuto para representar a marcação. Nesta versão, usaremos uma palavra incorporação para a entrada e manteremos a codificação única para a saída.

A forma como estruturamos cada sentença permanece a mesma, mas a forma como mapeamos cada token é alterada. A codificação de um tipo quente trata cada palavra como uma unidade isolada. Em vez disso, convertemos cada palavra nos dados de entrada para listas de dígitos. Estes representam a relação entre as tags de marcação.

A dimensão desta incorporação de palavras é de oito, mas muitas vezes varia entre 50-500 dependendo do tamanho do vocabulário.

Os oito dígitos para cada palavra são pesos semelhantes a uma rede neural de baunilha. Eles são sintonizados para mapear como as palavras se relacionam entre si ( Mikolov et al., 2013 ).

É assim que começamos a desenvolver recursos de marcação. As características são o que a rede neural desenvolve para vincular os dados de entrada com os dados de saída. Por enquanto, não se preocupe com o que são, nós aprofundaremos isso na próxima seção.

O codificador

Vamos levar a palavra embeddings e executá-los através de um LSTM e retornar uma seqüência de características de marcação. Estes são executados através de uma camada Densa distribuída no tempo – pense nela como uma camada densa com múltiplas entradas e saídas.

Em paralelo, os recursos da imagem são primeiro achatados. Independentemente de como os dígitos foram estruturados, eles são transformados em uma grande lista de números. Em seguida, aplicamos uma camada densa nesta camada para formar uma característica de alto nível. Esses recursos de imagem são então concatenados para os recursos de marcação.

Isso pode ser difícil de envolver sua mente – então vamos derrubar isso.

Características de marcação

Aqui executamos a palavra embeddings através da camada LSTM. Neste gráfico, todas as frases são preenchidas para atingir o tamanho máximo de três tokens.

Para misturar sinais e encontrar padrões de nível superior, aplicamos uma camada densa TimeDistributed para os recursos de marcação. TimeDistributed dense é o mesmo que uma camada densa, mas com múltiplas entradas e saídas.

Recursos de imagem

Paralelamente, preparamos as imagens. Nós levamos todos os mini recursos de imagem e os transformamos em uma lista longa. A informação não é alterada, apenas reorganizada.

Novamente, para misturar sinais e extrair noções de nível superior, aplicamos uma camada densa. Uma vez que estamos lidando apenas com um valor de entrada, podemos usar uma camada densa normal. Para conectar os recursos da imagem aos recursos de marcação, copiamos os recursos da imagem.

Neste caso, temos três características de marcação. Assim, acabamos com uma quantidade igual de recursos de imagem e recursos de marcação.

Concatenando os recursos de imagem e marcação

Todas as frases são preenchidas para criar três recursos de marcação. Uma vez que preparamos os recursos da imagem, agora podemos adicionar um recurso de imagem para cada recurso de marcação.

Depois de colar um recurso de imagem para cada recurso de marcação, acabamos com três recursos de marcação de imagem. Esta é a entrada que alimentamos no decodificador.

O decodificador

Aqui, usamos os recursos combinados de marcação de imagem para prever a próxima tag.

No exemplo abaixo, usamos três pares de recursos de marcação de imagem e exibimos um próximo recurso de tag.

Observe que a camada LSTM tem a seqüência definida como falsa. Em vez de retornar o comprimento da seqüência de entrada, ele apenas prevê uma característica. No nosso caso, é uma característica para a próxima tag. Contém a informação para a previsão final.

A previsão final

Se você não pode ver nada quando você clicar nesses links, você pode clicar com o botão direito do mouse e clicar em “Ver fonte da página”. Aqui está o site original para referência.

Erros que fiz:

  • LSTMs são muito mais pesados ??para minha cognição em comparação com CNNs . Quando eu desenrolava todos os LSTMs, eles se tornaram mais fáceis de entender. O vídeo de Fast.ai em RNNs foi super útil. Além disso, concentre-se nos recursos de entrada e saída antes de tentar entender como eles funcionam.
  • Construir um vocabulário desde o início é muito mais fácil do que reduzir um vocabulário enorme. Isso inclui tudo, desde fontes, tamanhos de div e cores hexadecimais até nomes de variáveis ??e palavras normais.
  • A maioria das bibliotecas são criadas para analisar documentos de texto e não código. Nos documentos, tudo é separado por um espaço, mas no código, você precisa de análise personalizada.
  • Você pode extrair recursos com um modelo treinado no Imagenet. Isso pode parecer contraintuitivo, uma vez que a Imagemet possui poucas imagens da web. No entanto, a perda é 30% maior em comparação com um modelo de pix2code, que é treinado a partir do zero. Seria interessante usar um tipo de modelo pré-treinamento com resnet com base em screenshots da web.

Versão Bootstrap

Em nossa versão final, usaremos um conjunto de dados de sites de bootstrap gerados a partir do papel pix2code. Ao usar o bootstrap do Twitter, podemos combinar HTML e CSS e diminuir o tamanho do vocabulário.

Vamos habilitá-lo a gerar a marcação para uma captura de tela que não viu antes. Também exploraremos como ele constrói conhecimento sobre a captura de tela e marcação.

Em vez de treiná-lo na marcação de inicialização, usaremos 17 tokens simplificados que traduzimos em HTML e CSS. O conjunto de dados inclui 1500 screenshots de teste e 250 imagens de validação. Para cada captura de tela há, em média, 65 tokens, resultando em 96925 exemplos de treinamento.

Ao ajustar o modelo no papel pix2code, o modelo pode prever os componentes da web com precisão de 97% (BLEU 4-ngram pesquisa gananciosa, mais sobre isso mais tarde).

Uma abordagem de ponta a ponta

Extrair recursos de modelos pré-treinados funciona bem em modelos de legendas de imagem. Mas depois de alguns experimentos, percebi que a abordagem de ponta a ponta do pix2code funciona melhor para esse problema. Os modelos pré-treinados não foram treinados em dados da web e são personalizados para classificação.

Neste modelo, substituímos os recursos de imagem pré-treinados por uma rede neuronal convolucional leve. Em vez de usar max-pooling para aumentar a densidade da informação, aumentamos os passos. Isso mantém a posição e a cor dos elementos front-end.

Existem dois modelos principais que permitem isso: redes neurais convolutivas (CNN) e redes neuronais recorrentes (RNN). A rede neural recorrente mais comum é a memória de longo prazo (LSTM), então é para isso que vou referir.

Há muitos excelentes tutoriais da CNN, e eu os abordei no meu artigo anterior . Aqui, vou me concentrar nos LSTMs.

Compreender timesteps em LSTMs

Uma das coisas mais difíceis de compreender sobre LSTMs é timestaps. Uma rede neural de baunilha pode ser pensada como dois timestaps. Se você dá “Olá”, ele prevê “Mundo”. Mas seria difícil prever mais timestaps. No exemplo abaixo, a entrada tem quatro timestaps, um para cada palavra.

Os LSTMs são feitos para entrada com timestaps. É uma rede neural personalizada para obter informações em ordem. Se você desenrola nosso modelo, parece assim. Para cada passo descendente, você mantém os mesmos pesos. Você aplica um conjunto de pesos ao resultado anterior e outro definido para a nova entrada.

A entrada ponderada e a saída são concatenadas e adicionadas em conjunto com uma ativação. Esta é a saída para esse timestep. Uma vez que reutilizamos os pesos, eles desenham informações de várias entradas e criam conhecimento da seqüência.

Aqui está uma versão simplificada do processo para cada timestep em um LSTM.

Para ter uma idéia dessa lógica, eu recomendaria criar uma RNN a partir do zero com o brilhante tutorial de Andrew Trask.

Compreendendo as unidades em camadas LSTM

O número de unidades em cada camada LSTM determina a capacidade de memorizar. Isso também corresponde ao tamanho de cada recurso de saída. Mais uma vez, uma característica é uma longa lista de números usados ??para transferir informações entre camadas.

Cada unidade na camada LSTM aprende a acompanhar diferentes aspectos da sintaxe. Abaixo está uma visualização de uma unidade que mantém faixas da informação na divisão da linha. Esta é a marcação simplificada que estamos usando para treinar o modelo de bootstrap.

Cada unidade LSTM mantém um estado celular. Pense no estado da célula como a memória. Os pesos e ativações são usados ??para modificar o estado de diferentes maneiras. Isso permite que as camadas LSTM aperfeiçoem as informações para manter e descartar para cada entrada.

É complicado encontrar uma maneira justa de medir a precisão. Diga que você compare, palavra a palavra. Se sua previsão é uma palavra fora de sincronia, você pode ter uma precisão de 0%. Se você remover uma palavra que sincroniza a previsão, você pode acabar com 99/100.

Usei a pontuação BLEU, a melhor prática na tradução de máquinas e modelos de legendas de imagem. Ele quebra a frase em quatro n gramas, de 1-4 seqüências de palavras. Na previsão abaixo, “gato” é suposto ser “código”.

Para obter o resultado final, você multiplica cada pontuação com 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. A soma é então multiplicada por uma pena de comprimento de sentença. Como o comprimento está correto em nosso exemplo, ele se torna nosso resultado final.

Você poderia aumentar o número de n-gramas para torná-lo mais difícil. Um modelo de quatro n gramas é o modelo que melhor corresponde às traduções humanas. Eu recomendaria executar alguns exemplos com o código abaixo e ler a página do wiki.

 #Crie uma função para ler um arquivo e retornar seu conteúdo 
 def load_doc (nome do arquivo): 
 arquivo = aberto (nome do arquivo, 'r') 
 text = file.read () 
 file.close () 
 retornar texto
 def load_data (data_dir): 
 text = [] 
 imagens = [] 
 files_in_folder = os.listdir (data_dir) 
 files_in_folder.sort () 
 para o nome do arquivo em tqdm (files_in_folder): 
 #Adicione uma imagem 
 se filename [-3:] == "npz": 
 image = np.load (data_dir + filename) 
 images.append (imagem ['features']) 
 outro: 
 # Adicione texto e envolva-o em uma etiqueta de início e fim 
 sintaxe = '<START>' + load_doc (data_dir + filename) + '<END>' 
 #Sense cada palavra com um espaço 
 syntax = '' .join (syntax.split ()) 
 #Adicione um espaço entre cada vírgula 
 syntax = syntax.replace (',', ',') 
 text.append (sintaxe) 
 images = np.array (images, dtype = float) 
 retornar imagens, texto
 #Inicialize a função para criar o vocabulário 
 tokenizer = Tokenizer (filtros = '', split = "", lower = False) 
 #Crie o vocabulário em uma ordem específica 
 tokenizer.fit_on_texts ([load_doc ('bootstrap.vocab')])
 dir_name = '../../../../eval/' 
 Train_features, texts = load_data (dir_name)
 # modelo de carga e pesos 
 json_file = open ('../../../../ model.json', 'r') 
 loaded_model_json = json_file.read () 
 json_file.close () 
 loaded_model = model_from_json (loaded_model_json) 
 # carregue pesos no novo modelo 
 loaded_model.load_weights ("../../../../ weights.hdf5") 
 imprimir ("modelo carregado do disco")
 # mapear um número inteiro para uma palavra 
 def word_for_id (inteiro, tokenizador): 
 por palavra, índice em tokenizer.word_index.items (): 
 se índice == inteiro: 
 palavra de retorno 
 retorno Nenhum 
 imprimir (word_for_id (17, tokenizer))
 # gerar uma descrição para uma imagem 
 def generate_desc (modelo, tokenizador, foto, max_length): 
 photo = np.array ([foto]) 
 # semeia o processo de geração 
 in_text = '<START>' 
 # iterar durante todo o comprimento da seqüência 
 print (' nPrediction ---->  n  n <START>', end = '') 
 para i no alcance (150): 
 # inteiro codifica sequência de entrada 
 sequence = tokenizer.texts_to_sequences ([in_text]) [0] 
 Entrada # pad 
 sequence = pad_sequences ([sequência], maxlen = max_length) 
 # preveja a próxima palavra 
 yhat = loaded_model.predict ([foto, sequência], verbose = 0) 
 # converte a probabilidade em número inteiro 
 yhat = argmax (yhat) 
 # mapa inteiro para palavra 
 word = word_for_id (yhat, tokenizer) 
 # pare se não podemos mapear a palavra 
 se a palavra for Nenhuma: 
 pausa 
 # acrescentar como entrada para gerar a próxima palavra 
 in_text + = word + '' 
 # pare se prevemos o fim da seqüência 
 imprimir (palavra + '', final = '') 
 se palavra == '<END>': 
 pausa 
 retornar em texto
 max_length = 48
 # avaliar a habilidade do modelo 
 def evaluation_model (modelo, descrições, fotos, tokenizador, max_length): 
 real, predito = lista (), lista () 
 # passo sobre o conjunto inteiro 
 para eu no alcance (len (textos)): 
 yhat = generate_desc (modelo, tokenizador, fotos [i], max_length) 
 # loja real e prevista 
 print (' n  nReal ---->  n  n' + textos [i]) 
 real.append ([textos [i] .split ()]) 
 predicted.append (yhat.split ()) 
 # calcular a pontuação BLEU 
 bleu = corpus_bleu (real, previsto) 
 retorno bleu, real, previsto
 bleu, real, forecasted = evaluation_model (loaded_model, texts, train_features, tokenizer, max_length)
 #Compile os tokens em HTML e css 
 dsl_path = "compilador / ativos / web-dsl-mapping.json" 
 compilador = compilador (dsl_path) 
 compiled_website = compilador.compile (predijo [0], 'index.html')
 imprimir (compilado_website) 
 imprimir (azul)

Saída

Links para saída de amostra

Erros que fiz:

  • Compreenda a fraqueza dos modelos em vez de testar modelos aleatórios. Primeiro, apliquei coisas aleatórias, como a normalização em lote e as redes bidirecionais, e tentei implementar a atenção. Depois de analisar os dados do teste e ver que não podia prever a cor e a posição com alta precisão, percebi que havia uma fraqueza na CNN. Isso me levou a substituir o maxpool com avanços. A perda de validação passou de 0,12 para 0,02 e aumentou a pontuação BLEU de 85% para 97%.
  • Use apenas modelos pré-treinados se forem relevantes. Dado o pequeno conjunto de dados, pensei que um modelo de imagem pré-treinada melhoraria o desempenho. Das minhas experiências, e o modelo de ponta a ponta é mais lento para treinar e requer mais memória, mas é mais preciso em 30%.
  • Planeje uma ligeira variação quando você executa seu modelo em um servidor remoto. No meu mac, ele lê os arquivos em ordem alfabética. No entanto, no servidor, foi localizado aleatoriamente. Isso criou uma incompatibilidade entre as capturas de tela e o código. Ainda convergiu, mas os dados de validação foram 50% pior do que quando eu corrigi.
  • Certifique-se de entender as funções da biblioteca. Inclua espaço para o token vazio em seu vocabulário. Quando não o adicionei, não incluiu um dos tokens. Eu só notei isso depois de olhar para o resultado final várias vezes e percebendo que nunca previu um token “único”. Depois de uma verificação rápida, percebi que nem sequer estava no vocabulário. Além disso, use a mesma ordem no vocabulário para treinar e testar.
  • Use modelos mais leves quando estiver experimentando. O uso de GRUs em vez de LSTM reduziu cada ciclo de época em 30% e não teve um grande efeito na performance.

Próximos passos

O desenvolvimento de front-end é um espaço ideal para aplicar o aprendizado profundo. É fácil gerar dados e os algoritmos de aprendizagem em profundidade atuais podem mapear a maior parte da lógica.

Uma das áreas mais interessantes é a atenção aos LSTMs . Isso não apenas melhorará a precisão, mas nos permitirá visualizar onde a CNN coloca seu foco, pois gera a marcação.

A atenção também é chave para a comunicação entre marcação, folhas de estilo, scripts e, eventualmente, o backend. As camadas de atenção podem acompanhar as variáveis, permitindo que a rede se comunique entre as linguagens de programação.

Mas, na característica próxima, o maior impacto virá da construção de uma maneira escalável para sintetizar dados. Então, você pode adicionar fontes, cores, palavras e animações passo a passo.

Até agora, a maior parte do progresso está acontecendo ao tirar esboços e transformá-los em aplicativos de modelo. Em menos de dois anos, poderemos desenhar um aplicativo em papel e ter o front-end correspondente em menos de um segundo. Já existem dois protótipos de trabalho construídos pela equipe de design da Airbnb e Uizard .

Aqui estão alguns experimentos para começar.

Experimentos

Começando

  • Execute todos os modelos
  • Experimente diferentes parâmetros hiper
  • Teste uma arquitetura CNN diferente
  • Adicionar modelos Bidirecionais LSTM
  • Implementar o modelo com um conjunto de dados diferente . (Você pode facilmente montar este conjunto de dados em seus trabalhos do FloydHub com este sinalizador – --data emilwallner/datasets/100k-html:data )

Outras experiências

  • Criando um gerador de aplicativo / web aleatório sólido com a sintaxe correspondente.
  • Dados para um esboço para o modelo do aplicativo. Converta automaticamente as capturas de tela do aplicativo / web em esboços e use um GAN para criar a variedade.
  • Aplique uma camada de atenção para visualizar o foco na imagem para cada previsão, semelhante a este modelo .
  • Crie uma estrutura para uma abordagem modular. Digamos, com modelos de encoder para fontes, um para cor, outro para layout e combiná-los com um decodificador. Um bom começo pode ser uma imagem sólida.
  • Alimente os componentes HTML simples da rede e ensine-o a gerar animações usando CSS. Seria fascinante ter uma abordagem de atenção e visualizar o foco em ambas as fontes de entrada.

Muito obrigado a Tony Beltramelli e Jon Gold por suas pesquisas e idéias, e por responder a perguntas. Graças a Jason Brownlee por seus tutoriais estelares da Keras (incluí alguns trechos do tutorial na implementação do Keras) e Beltramelli por fornecer os dados. Também graças a Qingping Hou, Charlie Harrington, Sai Soundararaj, Jannes Klaas, Claudio Cabral, Alain Demenet e Dylan Djian por ler rascunhos disso.

Sobre Emil Wallner

Esta é a quarta parte de uma série de blog de partes múltiplas de Emil enquanto ele aprende aprendizagem profunda. Emil passou uma década explorando a aprendizagem humana. Ele trabalhou para a escola de negócios de Oxford, investiu em startups de educação e construiu um negócio de tecnologia da educação. No ano passado, ele se matriculou na Ecole 42 para aplicar seu conhecimento da aprendizagem humana para o aprendizado automático.

Se você construir algo ou ficar preso, clique- me abaixo ou no twitter: emilwallner . Eu adoraria ver o que você está construindo.

Este foi publicado pela primeira vez como uma publicação da comunidade no blog do Floydhub .