了一整晚三个小时给大家整合的配色网站合集
希望看完可以评论点赞收藏或者转发都可以
adobe color
https://color.adobe.com/zh/explore/
搜索过去4000年来使用的180个调色板
https://colorleap.app/home
Picular是使用谷歌图像搜索的火箭快速原色发生器
https://picular.co/
自定义配色网站-我进去就蒙了
https://colourco.de/
对比度测试网站
https://colorable.jxnblk.com
Palettte App-最终的调色板编辑和重新映射工具
https://palettte.app
Colorinspire-精选色彩灵感
https://www.colorinspire.io
ColorSpace-调色板生成器和颜色渐变工具
https://mycolor.space
Pigment-大力推荐,谁用谁知道
https://pigment.shapefactory.co
Adobe Color-教科书式的取色(同类色、互补色、对比色...)
https://color.adobe.com/zh/create/color-wheel/
Colors & Fonts-调色板和字体配对灵感的集合
https://www.colorsandfonts.com
HueSnap-创建调色板并与他人共享
https://www.huesnap.com
Culrs-好像没什么特别
https://culrs.com/#/
Eva Design System-有点卡
https://eva.design
Scale-我词穷了,但是真的很棒
https://hihayk.github.io/scale/
Site Palette-真的编不下去了
https://palette.site
BrandColors-要不你们来试试?
https://brandcolors.net
Colorwise-Product Hunt中搜索投票最多的产品
https://colorwise.io
HTML Color Codes-作用不是太大
https://htmlcolorcodes.com
ColorBox-生成颜色集的颜色工具
https://www.colorbox.io
Generate — Coolors.co-一个打开很快的配色网站
https://coolors.co
Cloudflare Design-用于界面设计的调色板工具
https://cloudflare.design/color/
Instant Duotone Effect Generator-双色图
https://medialoot.com/duotones/
Color Tool-为UI创建和共享调色板
https://material.io/resources/color/#!/?view.left=0&view.right=0
Blendy-类似ps色彩蒙版
https://blendy.ml
LOL Colors-水滴形调色盘
https://www.webdesignrankings.com/resources/lolcolors/
Color Hunt-谁用谁知道
https://colorhunt.co
ColorMe-可视化CSS颜色功能
https://colorme.io
Gradient Hunt-渐变色
https://gradienthunt.com
ColorSpark-随机生成单色/渐变
https://colorspark.app
Sip-适用于Mac的Sip Color Picker
https://sipapp.io
CoolHue 2.0-获得免费的草图渐变颜色插件和渐变集合调色板
https://github.com/webkul/coolhue/releases
Color Koala-打开迅速
https://colorkoala.xyz
SchemeColor-用就完了
https://www.schemecolor.com
Free Mesh Gradient Collection-流体渐变
https://www.ls.graphics/meshgradients
WebGradients-支持下载psd和sketch格式
https://webgradients.com
Gradient Buttons-渐变
https://gradientbuttons.colorion.co
ColorKit-编不下去了,自己试试
https://colorkit.io
Eggradients
https://www.eggradients.com
Cool Backgrounds-超级牛逼的网站一定要试试大力推荐*****
随便下载一个都能去昵图上卖共享分你信我!!!
https://coolbackgrounds.io
GradPad-渐变色
http://ourownthing.co.uk/gradpad.html
Khroma-普通配色
http://khroma.co/train/
Color palettes-配色推荐
https://www.canva.com/colors/color-palettes/
Color Safe-搭配推荐
http://colorsafe.co
Paletton-
https://paletton.com
Colordot-不想配图,自己感受
https://color.hailpixel.com
Colors-
https://klart.io/colors
Contrast Ratio-轻松计算颜色对比度
https://contrast-ratio.com/#red-on-blue
Color Lisa-字体配色
http://colorlisa.com
Color Designer
https://colordesigner.io
Color.review-摸不着头脑
https://color.review
Blend-
http://www.colinkeany.com/blend/
Contrast-
https://usecontrast.com
Grabient-渐变
https://www.grabient.com
选自Floydhub
作者:Emil Wallner
机器之心编译
如何用前端页面原型生成对应的代码一直是我们关注的问题,本文作者根据 pix2code 等论文构建了一个强大的前端代码生成模型,并详细解释了如何利用 LSTM 与 CNN 将设计原型编写为 HTML 和 CSS 网站。
项目链接:github.com/emilwallner…
在未来三年内,深度学习将改变前端开发。它将会加快原型设计速度,拉低开发软件的门槛。
Tony Beltramelli 在去年发布了论文《pix2code: Generating Code from a Graphical User Interface Screenshot》,Airbnb 也发布Sketch2code(airbnb.design/sketching-i…)。
目前,自动化前端开发的最大阻碍是计算能力。但我们已经可以使用目前的深度学习算法,以及合成训练数据来探索人工智能自动构建前端的方法。在本文中,作者将教神经网络学习基于一张图片和一个设计模板来编写一个 HTML 和 CSS 网站。以下是该过程的简要概述:
1)向训练过的神经网络输入一个设计图
2)神经网络将图片转化为 HTML 标记语言
3)渲染输出
我们将分三步从易到难构建三个不同的模型,首先,我们构建最简单地版本来掌握移动部件。第二个版本 HTML 专注于自动化所有步骤,并简要解释神经网络层。在最后一个版本 Bootstrap 中,我们将创建一个模型来思考和探索 LSTM 层。
代码地址:
所有 FloydHub notebook 都在 floydhub 目录中,本地 notebook 在 local 目录中。
本文中的模型构建基于 Beltramelli 的论文《pix2code: Generating Code from a Graphical User Interface Screenshot》和 Jason Brownlee 的图像描述生成教程,并使用 Python 和 Keras 完成。
核心逻辑
我们的目标是构建一个神经网络,能够生成与截图对应的 HTML/CSS 标记语言。
训练神经网络时,你先提供几个截图和对应的 HTML 代码。网络通过逐个预测所有匹配的 HTML 标记语言来学习。预测下一个标记语言的标签时,网络接收到截图和之前所有正确的标记。
这里是一个简单的训练数据示例:docs.google.com/spreadsheet…。
创建逐词预测的模型是现在最常用的方法,也是本教程使用的方法。
注意:每次预测时,神经网络接收的是同样的截图。也就是说如果网络需要预测 20 个单词,它就会得到 20 次同样的设计截图。现在,不用管神经网络的工作原理,只需要专注于神经网络的输入和输出。
我们先来看前面的标记(markup)。假如我们训练神经网络的目的是预测句子「I can code」。当网络接收「I」时,预测「can」。下一次时,网络接收「I can」,预测「code」。它接收所有之前单词,但只预测下一个单词。
神经网络根据数据创建特征。神经网络构建特征以连接输入数据和输出数据。它必须创建表征来理解每个截图的内容和它所需要预测的 HTML 语法,这些都是为预测下一个标记构建知识。把训练好的模型应用到真实世界中和模型训练过程差不多。
我们无需输入正确的 HTML 标记,网络会接收它目前生成的标记,然后预测下一个标记。预测从「起始标签」(start tag)开始,到「结束标签」(end tag)终止,或者达到最大限制时终止。
Hello World 版
现在让我们构建 Hello World 版实现。我们将馈送一张带有「Hello World!」字样的截屏到神经网络中,并训练它生成对应的标记语言。
首先,神经网络将原型设计转换为一组像素值。且每一个像素点有 RGB 三个通道,每个通道的值都在 0-255 之间。
为了以神经网络能理解的方式表征这些标记,我使用了 one-hot 编码。因此句子「I can code」可以映射为以下形式。
在上图中,我们的编码包含了开始和结束的标签。这些标签能为神经网络提供开始预测和结束预测的位置信息。以下是这些标签的各种组合以及对应 one-hot 编码的情况。
我们会使每个单词在每一轮训练中改变位置,因此这允许模型学习序列而不是记忆词的位置。在下图中有四个预测,每一行是一个预测。且左边代表 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 版本中,我们使用三个符号「start」、「Hello World」和「end」。字符级的模型要求更小的词汇表和受限的神经网络,而单词级的符号在这里可能有更好的性能。
以下是执行预测的代码:
# 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=' ') 复制代码
输出
我走过的坑:
在 FloydHub 上运行代码
FloydHub 是一个深度学习训练平台,我自从开始学习深度学习时就对它有所了解,我也常用它训练和管理深度学习试验。我们能安装它并在 10 分钟内运行第一个模型,它是在云 GPU 上训练模型最好的选择。若果读者没用过 FloydHub,可以花 10 分钟左右安装并了解。
FloydHub 地址:www.floydhub.com/
复制 Repo:
https://github.com/emilwallner/Screenshot-to-code-in-Keras.git 复制代码
登录并初始化 FloydHub 命令行工具:
cd Screenshot-to-code-in-Keras floyd login floyd init s2c 复制代码
在 FloydHub 云 GPU 机器上运行 Jupyter notebook:
floyd run --gpu --env tensorflow-1.4 --data emilwallner/datasets/imagetocode/2:data --mode jupyter 复制代码
所有的 notebook 都放在 floydbub 目录下。一旦我们开始运行模型,那么在 floydhub/Helloworld/helloworld.ipynb 下可以找到第一个 Notebook。更多详情请查看本项目早期的 flags。
HTML 版本
在这个版本中,我们将关注与创建一个可扩展的神经网络模型。该版本并不能直接从随机网页预测 HTML,但它是探索动态问题不可缺少的步骤。
概览
如果我们将前面的架构扩展为以下右图展示的结构,那么它就能更高效地处理识别与转换过程。
该架构主要有两个部,即编码器与解码器。编码器是我们创建图像特征和前面标记特征(markup features)的部分。特征是网络创建原型设计和标记语言之间联系的构建块。在编码器的末尾,我们将图像特征传递给前面标记的每一个单词。随后解码器将结合原型设计特征和标记特征以创建下一个标签的特征,这一个特征可以通过全连接层预测下一个标签。
设计原型的特征
因为我们需要为每个单词插入一个截屏,这将会成为训练神经网络的瓶颈。因此我们抽取生成标记语言所需要的信息来替代直接使用图像。这些抽取的信息将通过预训练的 CNN 编码到图像特征中,且我们将使用分类层之前的层级输出以抽取特征。
我们最终得到 1536 个 8*8 的特征图,虽然我们很难直观地理解它,但神经网络能够从这些特征中抽取元素的对象和位置。
标记特征
在 Hello World 版本中,我们使用 one-hot 编码以表征标记。而在该版本中,我们将使用词嵌入表征输入并使用 one-hot 编码表示输出。我们构建每个句子的方式保持不变,但我们映射每个符号的方式将会变化。one-hot 编码将每一个词视为独立的单元,而词嵌入会将输入数据表征为一个实数列表,这些实数表示标记标签之间的关系。
上面词嵌入的维度为 8,但一般词嵌入的维度会根据词汇表的大小在 50 到 500 间变动。以上每个单词的八个数值就类似于神经网络中的权重,它们倾向于刻画单词之间的联系(Mikolov alt el., 2013)。这就是我们开始部署标记特征(markup features)的方式,而这些神经网络训练的特征会将输入数据和输出数据联系起来。
编码器
我们现在将词嵌入馈送到 LSTM 中,并期望能返回一系列的标记特征。这些标记特征随后会馈送到一个 Time Distributed 密集层,该层级可以视为有多个输入和输出的全连接层。
和嵌入与 LSTM 层相平行的还有另外一个处理过程,其中图像特征首先会展开成一个向量,然后再馈送到一个全连接层而抽取出高级特征。这些图像特征随后会与标记特征相级联而作为编码器的输出。
标记特征
如下图所示,现在我们将词嵌入投入到 LSTM 层中,所有的语句都会用零填充以获得相同的向量长度。
为了混合信号并寻找高级模式,我们运用了一个 TimeDistributed 密集层以抽取标记特征。TimeDistributed 密集层和一般的全连接层非常相似,且它有多个输入与输出。
图像特征
对于另一个平行的过程,我们需要将图像的所有像素值展开成一个向量,因此信息不会被改变,它们只会用来识别。
如上,我们会通过全连接层混合信号并抽取更高级的概念。因为我们并不只是处理一个输入值,因此使用一般的全连接层就行了。
级联图像特征和标记特征
所有的语句都被填充以创建三个标记特征。因为我们已经预处理了图像特征,所以我们能为每一个标记特征添加图像特征。
如上,在复制图像特征到对应的标记特征后,我们得到了新的图像-标记特征(image-markup features),这就是我们馈送到解码器的输入值。
解码器
现在,我们使用图像-标记特征来预测下一个标签。
在下面的案例中,我们使用三个图像-标签特征对来输出下一个标签特征。注意 LSTM 层不应该返回一个长度等于输入序列的向量,而只需要预测预测一个特征。在我们的案例中,这个特征将预测下一个标签,它包含了最后预测的信息。
最后的预测
密集层会像传统前馈网络那样工作,它将下一个标签特征中的 512 个值与最后的四个预测连接起来,即我们在词汇表所拥有的四个单词:start、hello、world 和 end。密集层最后采用的 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) 复制代码
输出
训练不同轮数所生成网站的地址:
我走过的坑:
Bootstrap 版本
在最终版本中,我们使用 pix2code 论文中生成 bootstrap 网站的数据集。使用 Twitter 的 Bootstrap 库(getbootstrap.com/),我们可以结合 HTML 和 CSS,降低词汇表规模。
我们将使用这一版本为之前未见过的截图生成标记。我们还深入研究它如何构建截图和标记的先验知识。
我们不在 bootstrap 标记上训练,而是使用 17 个简化 token,将其编译成 HTML 和 CSS。数据集(github.com/tonybeltram…)包括 1500 个测试截图和 250 个验证截图。平均每个截图有 65 个 token,一共有 96925 个训练样本。
我们稍微修改一下 pix2code 论文中的模型,使之预测网络组件的准确率达到 97%。
端到端方法
从预训练模型中提取特征在图像描述生成模型中效果很好。但是几次实验后,我发现 pix2code 的端到端方法效果更好。在我们的模型中,我们用轻量级卷积神经网络替换预训练图像特征。我们不使用最大池化来增加信息密度,而是增加步幅。这可以保持前端元素的位置和颜色。
存在两个核心模型:卷积神经网络(CNN)和循环神经网络(RNN)。最常用的循环神经网络是长短期记忆(LSTM)网络。我之前的文章中介绍过 CNN 教程,本文主要介绍 LSTM。
理解 LSTM 中的时间步
关于 LSTM 比较难理解的是时间步。我们的原始神经网络有两个时间步,如果你给它「Hello」,它就会预测「World」。但是它会试图预测更多时间步。下例中,输入有四个时间步,每个单词对应一个时间步。
LSTM 适合时序数据的输入,它是一种适合顺序信息的神经网络。模型展开图示如下,对于每个循环步,你需要保持同样的权重。
加权后的输入与输出特征在级联后输入到激活函数,并作为当前时间步的输出。因为我们重复利用了相同的权重,它们将从一些输入获取信息并构建序列的知识。下面是 LSTM 在每一个时间步上的简化版处理过程:
理解 LSTM 层级中的单元
每一层 LSTM 单元的总数决定了它记忆的能力,同样也对应于每一个输出特征的维度大小。LSTM 层级中的每一个单元将学习如何追踪句法的不同方面。以下是一个 LSTM 单元追踪标签行信息的可视化,它是我们用来训练 bootstrap 模型的简单标记语言。
每一个 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。如果你把百分百对照的单词移除一个,最终的准确率可能是 99/100。
我使用的是 BLEU 分值,它在机器翻译和图像描述模型实践上都是最好的。它把句子分解成 4 个 n-gram,从 1-4 个单词的序列。在下面的预测中,「cat」应该是「code」。
为了得到最终的分值,每个的分值需要乘以 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-gram 的数量,4 个 n-gram 的模型是最为对应人类翻译的。我建议你阅读下面的代码:
#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) 复制代码
输出
样本输出的链接:
我走过的坑:
下一步
前端开发是深度学习应用的理想空间。数据容易生成,并且当前深度学习算法可以映射绝大部分逻辑。一个最让人激动的领域是注意力机制在 LSTM 上的应用。这不仅会提升精确度,还可以使我们可视化 CNN 在生成标记时所聚焦的地方。注意力同样是标记、可定义模板、脚本和最终端之间通信的关键。注意力层要追踪变量,使网络可以在编程语言之间保持通信。
但是在不久的将来,最大的影响将会来自合成数据的可扩展方法。接着你可以一步步添加字体、颜色和动画。目前为止,大多数进步发生在草图(sketches)方面并将其转化为模版应用。在不到两年的时间里,我们将创建一个草图,它会在一秒之内找到相应的前端。Airbnb 设计团队与 Uizard 已经创建了两个正在使用的原型。下面是一些可能的试验过程:
实验
开始
进一步实验
原文链接:blog.floydhub.com/turning-des…
本文为机器之心编译,转载请联系本公众号获得授权。
文,我们将一起学习,使用纯 CSS,实现如下所示的动画效果:
上面的动画效果,非常有意思,核心有两点:
嗯?很有意思的效果。看上去,我们好像使用 CSS 实现了碰撞检测。
然而,实际情况真的是这样吗?让我们一起一探究竟!
这里其实我们并没有实现碰撞检测,因为小球和小球之间接触时,并没有发生碰撞效果。
我们只实现了,小球与边界之间的碰撞反应。不过这里,也并非碰撞检测,我们只需要设置好单个方向的运动动画,并且设置 animation-direction: alternate; 即可!
下面,我们一起来实现单个方向上的运动动画:
<div></div>
div {
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 100px;
border-radius: 50%;
background: #0cf;
animation: horizontal 3s infinite linear alternate;
}
@keyframes horizontal {
from {
left: 0;
}
to {
left: calc(100vw - 100px);
}
}
简单解读一下:
这样,我们就巧妙的实现了,在视觉上,小球元素移动到最右侧边界时,回弹的效果:
好,有了上面的铺垫,我们只需要再如法炮制 Y 轴方向的运动即可。
利用元素的 top 进行 Y 轴方向的运动:
div {
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 100px;
border-radius: 50%;
background: #0cf;
animation:
horizontal 3s infinite linear alternate,
vertical 3s infinite linear alternate;
}
@keyframes horizontal {
from {
left: 0;
}
to {
left: calc(100vw - 100px);
}
}
@keyframes vertical {
from {
top: 0;
}
to {
top: calc(100vh - 100px);
}
}
我们增加了一个 vertical 3s infinite linear alternate Y 轴的运动动画,实现小球从 top: 0 到 top: calc(100vh - 100px); 的运动。
这样,我们就成功的得到了 X、Y 两个方向上的小球运动,它们叠加在一起的效果如下:
当然,此时的问题在于,缺少了随机性,小球的始终在左上和右下角之间来回运动。
为了解决这个问题,我们需要添加一定的随机性,这个问题也要解决,我们只需要让两个方向上运动时间不一致即可。
我们修改一下代码,让 X、Y 轴的运动时长不一致即可:
div {
position: absolute;
// ...
animation:
horizontal 2.6s infinite linear alternate,
vertical 1.9s infinite linear alternate;
}
如此一来,整体的效果就好上了不少,由于整个动画是无限反复进行的,随着时间的推进,整个动画呈现出来的就是无序、随机的运动:
当然,上面的效果基本上没有什么太大的问题了,但是代码层面不够优雅,主要有两点问题:
上述两个问题,使用 transform: translate() 都可以解决,但是我们为什么一开始不用 transform 呢?
我们来尝试一下,使用 transform 替代 top、left:
div {
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 100px;
border-radius: 50%;
background: #0cf;
animation:
horizontal 2.6s infinite linear alternate,
vertical 1.9s infinite linear alternate;
}
@keyframes horizontal {
from { transform: translateX(0); }
to { transform: translateX(calc(100vw - 100%)); }
}
@keyframes vertical {
from { transform: translateY(0); }
to { transform: translateY(calc(100vh - 100%)); }
}
上述代码中,我们使用了 transform 替代 top、left 运动。并且,将动画代码中的 100px 替换成了 100%,这一点的好处是,在 transform: translate 中,100% 表示的是元素本身的高宽,这样,当我们改变元素本身的大小时,就无需再改变 @keyframes 中的代码,通用性更强。
我们来看看修改后的效果:
有点问题!预想中的效果并没有出现,整个动画只有 Y 轴方向上的动画效果。
这是什么原因呢?
其本质在于,定义的 vertical 1.9s infinite linear alternate 的垂直方向的动画效果覆盖了在其之前定义的 transform: translateX(calc(100vw - 100%)) 动画效果。
说人话就是 X、Y 轴的动画都使用了 transform 属性,两者之间造成了冲突。
在之前,这种情况基本是无解的,常见的解决方案就是:
不过,到今天,这个问题有了更好的解法!也就是 CSS animation 家族中的新属性 —— animation-composition。
这是一个非常新的属性,表示动画合成属性,从 Chrome 112 版本开始支持。
有三种不同的取值:
{
animation-composition: replace; // 表示动画值替换
animation-composition: add; // 表示动画值追加
animation-composition: accumulate; // 表示动画值累加
}
本文不会详细介绍 animation-composition,感兴趣的可以看看 MDN 的属性介绍或者 XBOXYAN 大佬的这篇文章 -- 了解一下全新的CSS动画合成属性animation-composition
这里,基于上面的代码,我们只需要再多设置一个 animation-composition: accumulate 即可解决问题:
div {
animation:
horizontal 2.6s infinite linear alternate,
vertical 1.9s infinite linear alternate;
animation-composition: accumulate;
}
此时,我们就能通过一个元素,利用 transform 得到 X、Y 两个方向位移动画的合成效果,也就是我们想要的效果:
解决了位移动画的问题,我们就只剩下最后一个问题了,如何在碰撞的瞬间,实现颜色的切换?
这里也非常好解决,由于我们是知道每一轮 X、Y 方向上的动画时长的,那我们只需要在每次这个结点上,切换一次颜色即可。
并且,由于颜色不是过渡变换,而是直接的跳变,所以,我们需要用到 animation 中的 animation-timing-function: steps(),也就是步骤缓动函数。
举个例子,假设 X 方向上,单次的动画时长为 3s,那我们可以设置一个 steps(10) 的颜色动画,总时长为 30s,这样,每隔 3s 就会触发一次 steps() 步骤动画,颜色的变化就能够和小球与边界的碰撞动画发生在同一时刻。
那如何快速实现颜色的变化呢?利用 filter: hue-rotate() 即可快速实现颜色的变化。
理解一下下面的代码:
<div class="normal"></div>
<div class="steps"></div>
div {
width: 200px;
height: 200px;
background: #fc0;
}
.normal {
animation: colorChange 10s linear infinite;
}
.steps {
animation: colorChange 10s steps(5) infinite;
}
@keyframes colorChange {
100% {
filter: hue-rotate(360deg);
}
}
这里,我们用 filter: hue-rotate(360deg) 的改变,实现颜色的变化,观察下面的动图,理解 steps(5) 的作用。
效果如下:
理解了这一步,我们就可以把颜色的变化,也一起叠加到上述的小球变化中:
div {
animation:
horizontal 2.6s infinite linear alternate,
vertical 2s infinite linear alternate,
colorX 26s infinite steps(10),
colorY 14s infinite steps(7);
animation-composition: accumulate;
}
@keyframes horizontal {
from { transform: translateX(0); }
to { transform: translateX(calc(100vw - 100%)); }
}
@keyframes vertical {
from { transform: translateY(0); }
to { transform: translateY(calc(100vh - 100%)); }
}
@keyframes colorX {
to {
filter: hue-rotate(360deg);
}
}
@keyframes colorY {
to {
filter: hue-rotate(360deg);
}
}
这样,我们就成功的得到了题图中的效果:
完整的代码,你可以戳这里:Random Circle Path
OK,上面,我们就把整个效果的完整原理剖析了一遍。
掌握了整个原理之后,我们就可以把这个效果应用于不同场景中。
譬如,假设我们有这么一张图片:
基于上面的效果,稍加改造,我们就可以得到类似的如下效果:
<div></div>
div {
width: 220px;
height: 97px;
background: linear-gradient(#f00, #f00), url(https://s1.ax1x.com/2023/08/15/pPQm9oT.jpg);
background-blend-mode: lighten;
background-size: contain;
animation: horizontal 3.7s infinite -1.4s linear alternate,
vertical 4.1s infinite -2.1s linear alternate,
colorX 37s infinite -1.4s steps(10),
colorY 28.7s infinite -2.1s steps(7);
animation-composition: accumulate;
}
@keyframes horizontal {
from { transform: translateX(0); }
to { transform: translateX(calc(100vw - 100%)); }
}
@keyframes vertical {
from { transform: translateY(0); }
to { transform: translateY(calc(100vh - 100%)); }
}
@keyframes colorX {
to {
filter: hue-rotate(2185deg);
}
}
@keyframes colorY {
to {
filter: hue-rotate(1769deg);
}
}
效果如下:
上面的 DEMO 是基于元素背景色的,本 DEMO 是基于图片的,因此这里多了一步,利用 mix-blend-mode,实现了图片颜色的变化。
完整的代码,你可以戳这里:CodePen Demo -- Random DVD Path
OK,我们再进一步,基于上面的效果,我们可以实现各种有趣的粒子效果,如果同时让页面存在 1000 个粒子呢?
下面是我使用 CSS-Doodle 实现的纯 CSS 的粒子效果,其核心原理与上面的保持一致,只是添加了更多的随机性:
Amazing!是不是非常有趣,整个效果的代码基于 CSS-doodle 的语法,不超过 40 行。完整的代码,你可以戳这里:CSS Doodle - CSS Particles Animation
总结一下,本文介绍了如何巧妙的利用 CSS 中的各种高阶技巧,组合实现类似于碰撞场景的动画效果。创建出了非常有趣的 CSS 动画,期间各种技巧的组合运用,值得好好琢磨学习。
链接:https://juejin.cn/post/7269797025863499837
*请认真填写需求信息,我们会在24小时内与您取得联系。