из Флойдхаба
Автор: Эмиль Вальнер.
Сборник "Сердце машины"
Нас всегда интересовало, как использовать прототип страницы интерфейса для генерации соответствующего кода.Автор этой статьи строит мощную модель генерации кода интерфейса на основе таких документов, как pix2code, и подробно объясняет, как использовать LSTM и CNN для написания прототипа дизайна веб-сайтов HTML и CSS.
Ссылка на проект:GitHub.com/Дочь Эмиля Уолла…
В ближайшие три года глубокое обучение изменит фронтенд-разработку. Это ускорит прототипирование и снизит порог для разработки программного обеспечения.
В прошлом году Тони Белтрамелли опубликовал документ «pix2code: Генерация кода из снимка экрана графического пользовательского интерфейса», а Airbnb также выпустила Sketch2code (воздух не NB.design/sketching-i…).
В настоящее время самым большим препятствием для автоматизации разработки интерфейса является вычислительная мощность. Но мы уже можем использовать существующие алгоритмы глубокого обучения, а также синтетические обучающие данные, чтобы изучить способы автоматического создания интерфейсов ИИ с помощью ИИ. В этой статье автор научит нейросеть писать сайт на HTML и CSS на основе изображения и шаблона дизайна. Вот краткий обзор процесса:
1) Введите расчетную схему в обученную нейронную сеть.
2) Нейронная сеть преобразует изображение в язык разметки HTML.
3) Рендеринг вывода
Мы создадим три разные модели в три шага от простого к сложному. Сначала мы создадим самую простую версию, чтобы освоить движущиеся части. Вторая версия HTML фокусируется на автоматизации всех шагов и кратко объясняет слои нейронной сети. В последней версии Bootstrap мы создадим модель для мышления и изучения слоев LSTM.
Кодовый адрес:
Все блокноты FloydHub находятся в каталоге floydhub, а локальные блокноты — в локальном каталоге.
Построение модели в этой статье основано на статье Белтрамелли «pix2code: Генерация кода из снимка экрана графического пользовательского интерфейса» и руководстве Джейсона Браунли по созданию описания изображения и выполняется с использованием Python и Keras.
основная логика
Наша цель — построить нейронную сеть, способную генерировать язык разметки HTML/CSS, соответствующий скриншотам.
При обучении нейронной сети вы сначала предоставляете несколько скриншотов и соответствующий HTML-код. Сеть обучается, предсказывая все совпадающие языки разметки HTML один за другим. При прогнозировании метки следующего языка разметки сеть получает скриншот и все предыдущие правильные метки.
Вот простой пример обучающих данных:docs.Google.com/spreadsheet….
Создание модели для пословного предсказания — наиболее распространенный метод в наши дни, именно он используется в этом руководстве.
Примечание. Нейронная сеть получает один и тот же снимок экрана каждый раз, когда делает прогноз. То есть, если сети нужно предсказать 20 слов, она получит один и тот же скриншот дизайна 20 раз. Теперь забудьте о том, как работает нейронная сеть, просто сосредоточьтесь на входе и выходе нейронной сети.
Давайте сначала посмотрим на предыдущую разметку. Предположим, цель обучения нейронной сети — предсказать предложение «Я умею кодировать». Когда сеть получает «я», предсказать «может». В следующий раз сеть получает «Я могу» и предсказывает «код». Он получает все предыдущие слова, но предсказывает только следующее слово.
Нейронные сети создают функции из данных. Нейронные сети создают функции для соединения входных и выходных данных. Он должен создавать представления, чтобы понять содержимое каждого снимка экрана и синтаксис HTML, который необходимо предсказать, чтобы получить знания для предсказания следующей разметки. Применение обученной модели к реальному миру похоже на процесс обучения модели.
Нам не нужно вводить правильную разметку HTML, сеть возьмет разметку, которую она сгенерировала до сих пор, и предскажет следующую. Предсказание начинается с «начального тега» и заканчивается «конечным тегом» или при достижении максимального предела.
Привет, мировое издание
Теперь давайте создадим нашу реализацию Hello World. Мы загрузим в нейронную сеть скриншот со словами «Hello World!» и обучим ее генерировать соответствующий язык разметки.
Сначала нейронная сеть преобразует дизайн прототипа в набор значений пикселей. И каждый пиксель имеет три канала RGB, и значение каждого канала находится в диапазоне от 0 до 255.
Чтобы представить эти токены таким образом, чтобы их могла понять нейронная сеть, я использую однократное кодирование. Таким образом, предложение «Я умею программировать» можно преобразовать в следующую форму.
На изображении выше наша кодировка содержит начальный и конечный теги. Эти метки предоставляют нейронной сети информацию о том, где начинать и заканчивать прогнозы. Вот различные комбинации этих меток и соответствующие им одноразовые кодировки.
Мы заставляем каждое слово менять позицию в каждом раунде обучения, поэтому это позволяет модели запоминать последовательность, а не запоминать позицию слова. На графике ниже четыре прогноза, каждая строка — прогноз. И левая сторона представляет трехцветный канал RGB и предыдущее слово, а правая сторона представляет результат прогнозирования и красный конечный тег.
#Length of longest sentence
max_caption_len = 3
#Size of vocabulary
vocab_size = 3
# Load one screenshot for each word and turn them into digits
images = []
for i in range(2):
images.append(img_to_array(load_img('screenshot.jpg', target_size=(224, 224))))
images = np.array(images, dtype=float)
# Preprocess input for the VGG16 model
images = preprocess_input(images)
#Turn start tokens into one-hot encoding
html_input = np.array(
[[[0., 0., 0.], #start
[0., 0., 0.],
[1., 0., 0.]],
[[0., 0., 0.], #start <HTML>Hello World!</HTML>
[1., 0., 0.],
[0., 1., 0.]]])
#Turn next word into one-hot encoding
next_words = np.array(
[[0., 1., 0.], # <HTML>Hello World!</HTML>
[0., 0., 1.]]) # end
# Load the VGG16 model trained on imagenet and output the classification feature
VGG = VGG16(weights='imagenet', include_top=True)
# Extract the features from the image
features = VGG.predict(images)
#Load the feature to the network, apply a dense layer, and repeat the vector
vgg_feature = Input(shape=(1000,))
vgg_feature_dense = Dense(5)(vgg_feature)
vgg_feature_repeat = RepeatVector(max_caption_len)(vgg_feature_dense)
# Extract information from the input seqence
language_input = Input(shape=(vocab_size, vocab_size))
language_model = LSTM(5, return_sequences=True)(language_input)
# Concatenate the information from the image and the input
decoder = concatenate([vgg_feature_repeat, language_model])
# Extract information from the concatenated output
decoder = LSTM(5, return_sequences=False)(decoder)
# Predict which word comes next
decoder_output = Dense(vocab_size, activation='softmax')(decoder)
# Compile and run the neural network
model = Model(inputs=[vgg_feature, language_input], outputs=decoder_output)
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
# Train the neural network
model.fit([features, html_input], next_words, batch_size=2, shuffle=False, epochs=1000)
В версии Hello World мы используем три символа «начало», «Hello World» и «конец». Модели на уровне символов требуют меньшего словаря и ограниченных нейронных сетей, в то время как символы на уровне слов могут работать здесь лучше.
Вот код для выполнения прогноза:
# 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=' ')
вывод
- 10 epochs: start start start
- 100 epochs: start <HTML><center><H1>Hello World!</H1></center></HTML> <HTML><center><H1>Hello World!</H1></center></HTML>
- 300 epochs: start <HTML><center><H1>Hello World!</H1></center></HTML> end
Яма, через которую я прошел:
- Создайте первую версию перед сбором данных. На ранних этапах этого проекта мне удалось получить устаревший архив сайта, размещенного на Geocities, который насчитывает 38 миллионов сайтов. Но я игнорирую огромный объем работы, необходимый для сокращения словарного запаса размером в 100 КБ.
- Обучение на терабайте данных требует отличного оборудования или огромного терпения. После нескольких проблем с моим Mac я использовал мощный удаленный сервер. Я рассчитываю арендовать 8 современных процессоров и 1 внутренний канал GPS для запуска моего рабочего процесса.
- Прежде чем понять входные и выходные данные, другие части, кажется, понимают. Вход X — это скриншот экрана и ранее отмеченная метка, а выход Y — следующая отмеченная метка. Когда я это понимаю, в других вопросах разобраться легче. Кроме того, будет проще попробовать другие архитектуры.
- Сеть преобразования изображения в код на самом деле является моделью, которая автоматически описывает изображения. Несмотря на то, что я понимаю это, я все еще скучаю по многим статьям об автоматическом суммировании изображений, потому что они выглядят недостаточно круто. Как только я понял это, мое понимание проблемного пространства стало намного глубже.
Запустить код на FloydHub
FloydHub — это платформа для обучения глубокому обучению, которую я знаю с тех пор, как начал изучать глубокое обучение, и я также использую ее для обучения и управления экспериментами по глубокому обучению. Мы смогли установить его и запустить нашу первую модель за 10 минут, и это лучший вариант для обучения моделей на облачных графических процессорах. Если читатель не использовал FloydHub, установка и понимание могут занять около 10 минут.
Адрес FloydHub:www.floydhub.com/
Скопируйте репо:
https://github.com/emilwallner/Screenshot-to-code-in-Keras.git
Войдите в систему и инициализируйте инструмент командной строки FloydHub:
cd Screenshot-to-code-in-Keras
floyd login
floyd init s2c
Запустите блокнот Jupyter на компьютере с облачным графическим процессором FloydHub:
floyd run --gpu --env tensorflow-1.4 --data emilwallner/datasets/imagetocode/2:data --mode jupyter
Все блокноты размещены в каталоге floydbub. Как только мы запустим модель, первую записную книжку можно будет найти в папке floydhub/Helloworld/helloworld.ipynb. См. флаги ранее в этом проекте для более подробной информации.
HTML-версия
В этом выпуске мы сосредоточимся на создании масштабируемой модели нейронной сети. Эта версия не предсказывает HTML напрямую из случайных веб-страниц, но это необходимый шаг в изучении динамических проблем.
Обзор
Если мы расширим предыдущую архитектуру до структуры, показанной справа ниже, она сможет более эффективно обрабатывать процесс распознавания и преобразования.
Архитектура в основном состоит из двух частей, а именно кодера и декодера. Кодер — это часть, в которой мы создаем функции изображения и предыдущие функции разметки. Функции — это строительные блоки, которые сеть создает связь между языками прототипирования и разметки. В конце кодировщика мы передаем признаки изображения каждому из ранее помеченных слов. Затем декодер объединит функции прототипирования и функции маркировки, чтобы создать следующую функцию метки, которая может быть предсказана полносвязным слоем.
Особенности дизайн-прототипов
Так как нам нужно вставлять скриншот для каждого слова, это станет узким местом для обучения нейросети. Таким образом, вместо того, чтобы напрямую использовать изображения, мы извлекаем информацию, необходимую для создания языка разметки. Эта извлеченная информация будет закодирована в функции изображения с помощью предварительно обученной CNN, и мы будем использовать выходные данные слоев перед слоем классификации для извлечения функций.
В итоге у нас получается 1536 карт признаков 8*8, и хотя нам сложно понять это интуитивно, нейронная сеть способна извлечь объект и расположение элементов из этих признаков.
функция маркера
В версии Hello World мы используем однократное кодирование для представления токенов. В этой версии мы будем использовать встраивание слов для представления входных данных и однократное кодирование для представления выходных данных. То, как мы строим каждое предложение, остается прежним, но то, как мы отображаем каждый символ, изменится. Горячее кодирование обрабатывает каждое слово как независимую единицу, в то время как встраивание слов представляет входные данные в виде списка действительных чисел, которые представляют отношения между метками токенов.
Размерность приведенного выше встраивания слов равна 8, но размерность общего встраивания слов будет варьироваться от 50 до 500 в зависимости от размера словаря. Приведенные выше восемь значений для каждого слова аналогичны весам в нейронных сетях, которые стремятся характеризовать связи между словами (Миколов и др., 2013). Вот как мы начали развертывать функции разметки, функции, на которых эти нейронные сети обучены связывать входные данные с выходными данными.
Кодер
Теперь мы передаем вложения слов в LSTM и ожидаем, что вернемся к последовательности помеченных функций. Эти помеченные объекты затем передаются в плотный слой Time Distributed, который можно рассматривать как полностью связанный слой с несколькими входами и выходами.
Параллельно со слоями внедрения и LSTM существует еще один процесс, в котором функции изображения сначала расширяются в вектор, а затем передаются на полностью связанный слой для извлечения функций высокого уровня. Эти функции изображения затем объединяются с функциями меток в качестве выходных данных кодировщика.
функция маркера
Как показано на изображении ниже, теперь мы добавляем вложения слов в слой LSTM, все предложения дополняются нулями, чтобы получить одинаковую длину вектора.
Чтобы смешать сигналы и найти шаблоны высокого уровня, мы применяем плотный слой TimeDistributed для извлечения помеченных функций. Плотный слой TimeDistributed очень похож на обычный полносвязный слой и имеет несколько входов и выходов.
особенности изображения
Для другого параллельного процесса нам нужно разложить все значения пикселей изображения в вектор, поэтому информация не изменится, они будут использоваться только для распознавания.
Как и выше, мы будем смешивать сигналы и извлекать концепции более высокого уровня через полностью связанные слои. Поскольку мы имеем дело не только с одним входным значением, будет достаточно обычного полносвязного слоя.
Каскадные функции изображения и функции маркировки
Все операторы заполняются для создания трех объектов-маркеров. Поскольку мы предварительно обработали функции изображения, мы можем добавить функции изображения к каждой помеченной функции.
Как и выше, после копирования признаков изображения в соответствующие признаки разметки мы получаем новые признаки разметки изображения, которые являются входными значениями, которые мы передаем декодеру.
декодер
Теперь мы используем функции метки изображения, чтобы предсказать следующую метку.
В приведенном ниже примере мы используем три пары функций изображения и метки для вывода следующей функции метки. Обратите внимание, что слой LSTM не должен возвращать вектор длины, равной входной последовательности, а должен только предсказывать функцию. В нашем случае эта функция будет предсказывать следующую метку, содержащую последнюю предсказанную информацию.
окончательный прогноз
Плотный слой будет работать как традиционная сеть прямой связи, соединяя 512 значений в следующей функции метки с последними четырьмя предсказаниями, четырьмя словами, которые у нас есть в словаре: начало, привет, мир и конец. Функция softmax в конце плотного слоя создает распределение вероятностей для четырех классов, например [0,1, 0,1, 0,1, 0,7] будет предсказывать четвертое слово в качестве следующей метки.
# Load the images and preprocess them for inception-resnet
images = []
all_filenames = listdir('images/')
all_filenames.sort()
for filename in all_filenames:
images.append(img_to_array(load_img('images/'+filename, target_size=(299, 299))))
images = np.array(images, dtype=float)
images = preprocess_input(images)
# Run the images through inception-resnet and extract the features without the classification layer
IR2 = InceptionResNetV2(weights='imagenet', include_top=False)
features = IR2.predict(images)
# We will cap each input sequence to 100 tokens
max_caption_len = 100
# Initialize the function that will create our vocabulary
tokenizer = Tokenizer(filters='', split=" ", lower=False)
# Read a document and return a string
def load_doc(filename):
file = open(filename, 'r')
text = file.read()
file.close()
return text
# Load all the HTML files
X = []
all_filenames = listdir('html/')
all_filenames.sort()
for filename in all_filenames:
X.append(load_doc('html/'+filename))
# Create the vocabulary from the html files
tokenizer.fit_on_texts(X)
# Add +1 to leave space for empty words
vocab_size = len(tokenizer.word_index) + 1
# Translate each word in text file to the matching vocabulary index
sequences = tokenizer.texts_to_sequences(X)
# The longest HTML file
max_length = max(len(s) for s in sequences)
# Intialize our final input to the model
X, y, image_data = list(), list(), list()
for img_no, seq in enumerate(sequences):
for i in range(1, len(seq)):
# Add the entire sequence to the input and only keep the next word for the output
in_seq, out_seq = seq[:i], seq[i]
# If the sentence is shorter than max_length, fill it up with empty words
in_seq = pad_sequences([in_seq], maxlen=max_length)[0]
# Map the output to one-hot encoding
out_seq = to_categorical([out_seq], num_classes=vocab_size)[0]
# Add and image corresponding to the HTML file
image_data.append(features[img_no])
# Cut the input sentence to 100 tokens, and add it to the input data
X.append(in_seq[-100:])
y.append(out_seq)
X, y, image_data = np.array(X), np.array(y), np.array(image_data)
# Create the encoder
image_features = Input(shape=(8, 8, 1536,))
image_flat = Flatten()(image_features)
image_flat = Dense(128, activation='relu')(image_flat)
ir2_out = RepeatVector(max_caption_len)(image_flat)
language_input = Input(shape=(max_caption_len,))
language_model = Embedding(vocab_size, 200, input_length=max_caption_len)(language_input)
language_model = LSTM(256, return_sequences=True)(language_model)
language_model = LSTM(256, return_sequences=True)(language_model)
language_model = TimeDistributed(Dense(128, activation='relu'))(language_model)
# Create the decoder
decoder = concatenate([ir2_out, language_model])
decoder = LSTM(512, return_sequences=False)(decoder)
decoder_output = Dense(vocab_size, activation='softmax')(decoder)
# Compile the model
model = Model(inputs=[image_features, language_input], outputs=decoder_output)
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
# Train the neural network
model.fit([image_data, X], y, batch_size=64, shuffle=False, epochs=2)
# map an integer to a word
def word_for_id(integer, tokenizer):
for word, index in tokenizer.word_index.items():
if index == integer:
return word
return None
# generate a description for an image
def generate_desc(model, tokenizer, photo, max_length):
# seed the generation process
in_text = 'START'
# iterate over the whole length of the sequence
for i in range(900):
# integer encode input sequence
sequence = tokenizer.texts_to_sequences([in_text])[0][-100:]
# pad input
sequence = pad_sequences([sequence], maxlen=max_length)
# predict next word
yhat = model.predict([photo,sequence], verbose=0)
# convert probability to integer
yhat = np.argmax(yhat)
# map integer to word
word = word_for_id(yhat, tokenizer)
# stop if we cannot map the word
if word is None:
break
# append as input for generating the next word
in_text += ' ' + word
# Print the prediction
print(' ' + word, end='')
# stop if we predict the end of the sequence
if word == 'END':
break
return
# Load and image, preprocess it for IR2, extract features and generate the HTML
test_image = img_to_array(load_img('images/87.jpg', target_size=(299, 299)))
test_image = np.array(test_image, dtype=float)
test_image = preprocess_input(test_image)
test_features = IR2.predict(np.array([test_image]))
generate_desc(model, tokenizer, np.array(test_features), 100)
вывод
Адреса сайтов, сгенерированных обучением разных эпох:
- 250 эпох:Эмиль Уолл Дочь.GitHub.IO/HTML/250_EP…
- 350 эпох:Эмиль Уолл Дочь.GitHub.IO/HTML/350_EP…
- 450 эпох:Эмиль Уолл Дочь.GitHub.IO/HTML/450_EP…
- 550 эпох:Эмиль Уолл Дочь.GitHub.IO/HTML/550_EP…
Яма, через которую я прошел:
- Я думаю, что понять LSTM немного сложнее, чем CNN. Их становится немного легче понять, когда я расширяю LSTM. Кроме того, мы можем сосредоточиться на функциях ввода и вывода, прежде чем пытаться понять LSTM.
- Гораздо проще построить словарь с нуля, чем сжимать огромный словарный запас. Такие сборки включают шрифты, размеры тегов div, шестнадцатеричные цвета для имен переменных и общие слова.
- Большинство библиотек созданы для разбора текстовых документов. В документации по использованию библиотеки нам скажут, как разбивать по пробелам, а не по коду, нам нужно настроить способ парсинга.
- Мы можем извлекать признаки из моделей, предварительно обученных в ImageNet. Однако потери примерно на 30% выше по сравнению с моделью pix2code, обученной de novo. Кроме того, я заинтересован в использовании сети inception-resnet, предварительно обученной на основе веб-снимков экрана.
Начальная версия
В окончательной версии мы используем набор данных из статьи pix2code для создания загрузочного веб-сайта. Используйте библиотеку Twitter Bootstrap (getbootstrap.com/), мы можем комбинировать HTML и CSS, чтобы уменьшить размер словаря.
Мы будем использовать эту версию для создания разметки для скриншотов, которых мы раньше не видели. Мы также углубимся в то, как он формирует предварительные знания о снимках экрана и разметке.
Вместо обучения на загрузочных токенах мы используем 17 упрощенных токенов, которые скомпилированы в HTML и CSS. набор данных(GitHub.com/Tony Belt RAM…) включает 1500 тестовых снимков экрана и 250 проверочных снимков экрана. В среднем на каждый скриншот приходится 65 токенов, всего 96925 обучающих выборок.
Мы немного изменили модель в документе pix2code, чтобы прогнозировать компоненты сети с точностью 97%.
комплексный подход
Извлечение признаков из предварительно обученных моделей хорошо работает в генеративных моделях описания изображений. Но после нескольких экспериментов я обнаружил, что сквозной подход pix2code работает лучше. В нашей модели мы заменяем предварительно обученные функции изображения облегченными сверточными нейронными сетями. Вместо того, чтобы использовать максимальное объединение для увеличения плотности информации, мы увеличиваем шаг. Это сохраняет положение и цвет элементов интерфейса.
Существуют две основные модели: сверточные нейронные сети (CNN) и рекуррентные нейронные сети (RNN). Наиболее часто используемой рекуррентной нейронной сетью является сеть с долговременной кратковременной памятью (LSTM). Я рассмотрел учебник по CNN в своей предыдущей статье, а эта статья посвящена LSTM.
Понимание временных шагов в LSTM
Самое сложное для понимания в LSTM — это временной шаг. Наша исходная нейронная сеть имеет два временных шага, и если вы дадите ей «Привет», она предскажет «Мир». Но он попытается предсказать больше временных шагов. В приведенном ниже примере входные данные имеют четыре временных шага, по одному для каждого слова.
LSTM подходит для ввода данных временных рядов, это своего рода нейронная сеть, подходящая для последовательной информации. Модель разворачивается, как показано ниже, для каждого шага петли нужно сохранять одинаковые веса.
Взвешенные входные и выходные функции каскадируются и подаются в функцию активации в качестве выходных данных на текущем временном шаге. Поскольку мы повторно используем одни и те же веса, они будут получать информацию из некоторых входных данных и формировать знания о последовательности. Вот упрощенная версия обработки LSTM на каждом временном шаге:
Понимание единиц в иерархии LSTM
Общее количество единиц LSTM в каждом слое определяет его объем памяти, который также соответствует размеру каждого выходного объекта. Каждый модуль в иерархии LSTM научится отслеживать различные аспекты синтаксиса. Ниже представлена визуализация информации о строке метки, отслеживаемой модулем LSTM, простым языком разметки, который мы используем для обучения нашей модели начальной загрузки.
Каждая ячейка LSTM поддерживает состояние ячейки, которое мы можем рассматривать как память. Веса и активации могут по-разному изменять значения состояния, что позволяет точно настраивать слои LSTM, сохраняя или забывая входную информацию. Помимо обработки текущей входной и выходной информации, ячейке LSTM также необходимо изменить состояние памяти, чтобы перейти к следующему временному шагу.
dir_name = 'resources/eval_light/'
# Read a file and return a string
def load_doc(filename):
file = open(filename, 'r')
text = file.read()
file.close()
return text
def load_data(data_dir):
text = []
images = []
# Load all the files and order them
all_filenames = listdir(data_dir)
all_filenames.sort()
for filename in (all_filenames):
if filename[-3:] == "npz":
# Load the images already prepared in arrays
image = np.load(data_dir+filename)
images.append(image['features'])
else:
# Load the boostrap tokens and rap them in a start and end tag
syntax = '<START> ' + load_doc(data_dir+filename) + ' <END>'
# Seperate all the words with a single space
syntax = ' '.join(syntax.split())
# Add a space after each comma
syntax = syntax.replace(',', ' ,')
text.append(syntax)
images = np.array(images, dtype=float)
return images, text
train_features, texts = load_data(dir_name)
# Initialize the function to create the vocabulary
tokenizer = Tokenizer(filters='', split=" ", lower=False)
# Create the vocabulary
tokenizer.fit_on_texts([load_doc('bootstrap.vocab')])
# Add one spot for the empty word in the vocabulary
vocab_size = len(tokenizer.word_index) + 1
# Map the input sentences into the vocabulary indexes
train_sequences = tokenizer.texts_to_sequences(texts)
# The longest set of boostrap tokens
max_sequence = max(len(s) for s in train_sequences)
# Specify how many tokens to have in each input sentence
max_length = 48
def preprocess_data(sequences, features):
X, y, image_data = list(), list(), list()
for img_no, seq in enumerate(sequences):
for i in range(1, len(seq)):
# Add the sentence until the current count(i) and add the current count to the output
in_seq, out_seq = seq[:i], seq[i]
# Pad all the input token sentences to max_sequence
in_seq = pad_sequences([in_seq], maxlen=max_sequence)[0]
# Turn the output into one-hot encoding
out_seq = to_categorical([out_seq], num_classes=vocab_size)[0]
# Add the corresponding image to the boostrap token file
image_data.append(features[img_no])
# Cap the input sentence to 48 tokens and add it
X.append(in_seq[-48:])
y.append(out_seq)
return np.array(X), np.array(y), np.array(image_data)
X, y, image_data = preprocess_data(train_sequences, train_features)
#Create the encoder
image_model = Sequential()
image_model.add(Conv2D(16, (3, 3), padding='valid', activation='relu', input_shape=(256, 256, 3,)))
image_model.add(Conv2D(16, (3,3), activation='relu', padding='same', strides=2))
image_model.add(Conv2D(32, (3,3), activation='relu', padding='same'))
image_model.add(Conv2D(32, (3,3), activation='relu', padding='same', strides=2))
image_model.add(Conv2D(64, (3,3), activation='relu', padding='same'))
image_model.add(Conv2D(64, (3,3), activation='relu', padding='same', strides=2))
image_model.add(Conv2D(128, (3,3), activation='relu', padding='same'))
image_model.add(Flatten())
image_model.add(Dense(1024, activation='relu'))
image_model.add(Dropout(0.3))
image_model.add(Dense(1024, activation='relu'))
image_model.add(Dropout(0.3))
image_model.add(RepeatVector(max_length))
visual_input = Input(shape=(256, 256, 3,))
encoded_image = image_model(visual_input)
language_input = Input(shape=(max_length,))
language_model = Embedding(vocab_size, 50, input_length=max_length, mask_zero=True)(language_input)
language_model = LSTM(128, return_sequences=True)(language_model)
language_model = LSTM(128, return_sequences=True)(language_model)
#Create the decoder
decoder = concatenate([encoded_image, language_model])
decoder = LSTM(512, return_sequences=True)(decoder)
decoder = LSTM(512, return_sequences=False)(decoder)
decoder = Dense(vocab_size, activation='softmax')(decoder)
# Compile the model
model = Model(inputs=[visual_input, language_input], outputs=decoder)
optimizer = RMSprop(lr=0.0001, clipvalue=1.0)
model.compile(loss='categorical_crossentropy', optimizer=optimizer)
#Save the model for every 2nd epoch
filepath="org-weights-epoch-{epoch:04d}--val_loss-{val_loss:.4f}--loss-{loss:.4f}.hdf5"
checkpoint = ModelCheckpoint(filepath, monitor='val_loss', verbose=1, save_weights_only=True, period=2)
callbacks_list = [checkpoint]
# Train the model
model.fit([image_data, X], y, batch_size=64, shuffle=False, validation_split=0.1, callbacks=callbacks_list, verbose=1, epochs=50)
точность теста
Найти хороший способ измерения точности непросто. Например, пословное сравнение, если одно из ваших предсказаний не сравнивается, показатель точности может быть равен 0. Если вы удалите одно слово, которое сравнивается на 100%, окончательная точность может составить 99/100.
Я использую оценку BLEU, которая является наилучшей на практике как для моделей машинного перевода, так и для моделей подписей к изображениям. Он разбивает предложения на 4 n-грамма из последовательностей из 1-4 слов. В приведенном ниже прогнозе «кошка» должна быть «кодом».
Чтобы получить окончательный балл, каждый балл необходимо умножить на 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. Затем сумма умножается на функцию штрафа за длину предложения. Поскольку длина в нашем примере верна, это непосредственно наша окончательная оценка.
Вы можете увеличить количество n-грамм, модель с 4 n-граммами лучше всего подходит для человеческого перевода. Я предлагаю вам прочитать код ниже:
#Create a function to read a file and return its content
def load_doc(filename):
file = open(filename, 'r')
text = file.read()
file.close()
return text
def load_data(data_dir):
text = []
images = []
files_in_folder = os.listdir(data_dir)
files_in_folder.sort()
for filename in tqdm(files_in_folder):
#Add an image
if filename[-3:] == "npz":
image = np.load(data_dir+filename)
images.append(image['features'])
else:
# Add text and wrap it in a start and end tag
syntax = '<START> ' + load_doc(data_dir+filename) + ' <END>'
#Seperate each word with a space
syntax = ' '.join(syntax.split())
#Add a space between each comma
syntax = syntax.replace(',', ' ,')
text.append(syntax)
images = np.array(images, dtype=float)
return images, text
#Intialize the function to create the vocabulary
tokenizer = Tokenizer(filters='', split=" ", lower=False)
#Create the vocabulary in a specific order
tokenizer.fit_on_texts([load_doc('bootstrap.vocab')])
dir_name = '../../../../eval/'
train_features, texts = load_data(dir_name)
#load model and weights
json_file = open('../../../../model.json', 'r')
loaded_model_json = json_file.read()
json_file.close()
loaded_model = model_from_json(loaded_model_json)
# load weights into new model
loaded_model.load_weights("../../../../weights.hdf5")
print("Loaded model from disk")
# map an integer to a word
def word_for_id(integer, tokenizer):
for word, index in tokenizer.word_index.items():
if index == integer:
return word
return None
print(word_for_id(17, tokenizer))
# generate a description for an image
def generate_desc(model, tokenizer, photo, max_length):
photo = np.array([photo])
# seed the generation process
in_text = '<START> '
# iterate over the whole length of the sequence
print('\nPrediction---->\n\n<START> ', end='')
for i in range(150):
# integer encode input sequence
sequence = tokenizer.texts_to_sequences([in_text])[0]
# pad input
sequence = pad_sequences([sequence], maxlen=max_length)
# predict next word
yhat = loaded_model.predict([photo, sequence], verbose=0)
# convert probability to integer
yhat = argmax(yhat)
# map integer to word
word = word_for_id(yhat, tokenizer)
# stop if we cannot map the word
if word is None:
break
# append as input for generating the next word
in_text += word + ' '
# stop if we predict the end of the sequence
print(word + ' ', end='')
if word == '<END>':
break
return in_text
max_length = 48
# evaluate the skill of the model
def evaluate_model(model, descriptions, photos, tokenizer, max_length):
actual, predicted = list(), list()
# step over the whole set
for i in range(len(texts)):
yhat = generate_desc(model, tokenizer, photos[i], max_length)
# store actual and predicted
print('\n\nReal---->\n\n' + texts[i])
actual.append([texts[i].split()])
predicted.append(yhat.split())
# calculate BLEU score
bleu = corpus_bleu(actual, predicted)
return bleu, actual, predicted
bleu, actual, predicted = evaluate_model(loaded_model, texts, train_features, tokenizer, max_length)
#Compile the tokens into HTML and css
dsl_path = "compiler/assets/web-dsl-mapping.json"
compiler = Compiler(dsl_path)
compiled_website = compiler.compile(predicted[0], 'index.html')
print(compiled_website )
print(bleu)
вывод
Ссылка на образец вывода:
- Generated website 1 - Original 1 (Эмиль Уолл Дочь.GitHub.IO/bootstrap/th…)
- Generated website 2 - Original 2 (Дочь Эмиля Уолла, GitHub.IO/bootstrap/th…)
- Generated website 3 - Original 3 (Дочь Эмиля Уолла, GitHub.IO/bootstrap/th…)
- Generated website 4 - Original 4 (Дочь Эмиля Уолла, GitHub.IO/bootstrap/th…)
- Generated website 5 - Original 5 (Дочь Эмиля Уолла, GitHub.IO/bootstrap/th…)
Яма, через которую я прошел:
- Понимание слабых сторон модели вместо тестирования случайных моделей. Сначала я использую случайные вещи, такие как нормализация пакетов, двунаправленная сеть и пытаюсь реализовать механизм внимания. Посмотрев на тестовые данные и зная, что он не может предсказать цвет и положение с высокой точностью, я понял, что у CNN есть слабость. Это привело меня к использованию увеличенного шага вместо максимального объединения. Потери при проверке уменьшились с 0,12 до 0,02, а показатель BLEU увеличился с 85% до 97%.
- Используйте предварительно обученную модель только в том случае, если они связаны. Я думаю, что в случае небольших данных предварительно обученная модель изображения улучшит производительность. Из моих экспериментов сквозная модель обучается медленнее и требует больше памяти, но повышает точность на 30%.
- Когда вы запускаете модель на удаленном сервере, нам нужно подготовиться к нескольким отличиям. На моем Mac он читает документы в алфавитном порядке. Но на сервере он расположен рандомно. Это создает несоответствие между кодом и скриншотом.
Следующий шаг
Фронтенд-разработка — идеальное место для приложений глубокого обучения. Данные легко генерировать, и современные алгоритмы глубокого обучения могут отображать большую часть логики. Одной из самых интересных областей является применение механизмов внимания к LSTM. Это не только повышает точность, но также позволяет нам визуализировать, где фокусируется CNN при создании маркеров. Внимание также является ключом к взаимодействию между разметкой, определяемыми шаблонами, сценариями и, в конечном счете, терминалами. Уровень внимания отслеживает переменные, чтобы сеть могла взаимодействовать между языками программирования.
Но в ближайшем будущем наибольшее влияние окажут масштабируемые подходы к синтетическим данным. Затем вы можете шаг за шагом добавлять шрифты, цвета и анимацию. До сих пор большая часть прогресса происходила в эскизах и превращалась в трафаретные аппликации. Менее чем за два года мы создадим скетч, который за секунду найдет соответствующий интерфейс. Команда дизайнеров Airbnb и Уизард создали два рабочих прототипа. Вот некоторые возможные пробные процедуры:
эксперимент
Начинать
- запустить все модели
- попробуйте разные гиперпараметры
- Протестируйте другую архитектуру CNN
- Добавьте двунаправленную модель LSTM
- Внедрение моделей с различными наборами данных
Дальнейшие эксперименты
- Создайте стабильный генератор случайных приложений/веб-страниц с соответствующим синтаксисом.
- Данные от эскизов до прикладных моделей. Автоматически преобразовывайте скриншоты приложений/веб-страниц в эскизы и используйте GAN для создания разнообразия.
- Примените слой внимания, чтобы визуализировать каждый прогнозируемый фокус изображения, как в этой модели.
- Создайте основу для модульного подхода. Например, у вас есть модели кодировщика для шрифтов, одна для цвета, а другая для типографики, и используйте декодер для их интеграции. Стабильные функции изображения — хорошее начало.
- Скармливайте простые HTML-компоненты нейронной сети и научите ее анимировать с помощью CSS. Было бы интересно использовать метод внимания и визуализировать фокус двух входных источников.
Оригинальная ссылка:blog.Floyd hub.com/turning-things…
Эта статья составлена для ядра машины, пожалуйста, свяжитесь с этой общедоступной учетной записью для разрешения на перепечатку.