如何训练Keras模型以生成颜色
概观
选择一种语言模型以最好地表示输入文本
清理并准备培训数据
建立一个基本的Keras时序神经网络模型。
应用递归神经网络(RNN)处理字符序列。
生成3通道RGB彩色输出。
构建概述
语言模型
语言建模有两个通用选项:词级模型和字符级模型。各有其优点和缺点。现在让我们来看看它们。
词级语言模型
单词级语言模型可以处理相对较长且干净的句子。“clean”是指文本数据集中的单词不含拼写错误,在英语词汇之外几乎没有单词。单词级语言模型将每个唯一单词编码为相应的整数,并且有一个预定义的固定大小的词汇表字典来查找单词到整数映射。单词级语言模型的一个主要优点是它能够利用预先训练的词嵌入,如Word2Vec或GLOVE。这些嵌入将单词表示为具有有用属性的向量。上下文中接近的词在欧几里德距离上接近,可以用来理解类比,比如“男人对女人,对国王来说是女王”。使用这些想法,您可以训练一个带有相对较小标签的训练集的词级模型。
字符级语言模型
但是还有一种更简单的语言模型,它将文本字符串拆分为字符,并将唯一的整数与每个字符相关联。您可能会选择使用字符级语言模型而不是更受欢迎的字级模型:
您的文本数据集包含大量词外单词或不常用单词。在我们的案例中,一些合法的颜色名称可能是“aquatone”,“chartreuse”和“fuchsia”。对于我来说,我必须检查字典并找出它们的含义,而传统的字级嵌入可能不包含它们。
大部分文本字符串都是短的,有限长度的字符串。通常,字符级语言生成模型可以创建更多种类的文本,因为其想象力不受预定词汇表的限制。
您也可能会意识到采用字符级语言所带来的局限性:
长序列可能无法捕获远程依赖关系以及词级语言模型。
字符级模型在训练中的计算量也更大 - 给定相同的文本数据集,这些模型序列更长,因此需要更长的训练时间。
幸运的是,这些限制不会对我们的颜色生成任务构成威胁。我们将颜色名称限制为25个字符,我们只有14157个训练样本。
数据准备
数据集中的前5行
我们提到我们将颜色名称限制为25个字符。为了达到这个数字,我们检查了所有训练样本中颜色名称长度的分布并将其可视化,以确保我们选择的长度限制是合理的。
h = sorted(names.str.len().as_matrix())
import numpy as np
import scipy.stats as stats
import pylab as plt
fit = stats.norm.pdf(h, np.mean(h), np.std(h)) #this is a fitting indeed
plt.plot(h,fit,'-o')
plt.hist(h,normed=True) #use this to draw histogram of your data
plt.xlabel('Chars')
plt.ylabel('Probability density')
plt.show()
这给了我们这个图,并且您可以清楚地看到大多数颜色名称字符串的长度小于或等于25,即使最大长度达到30。
在我们的例子中,我们可以选择30的最大长度,但是我们要构建的模型也需要长时间训练更长的序列。我们选择较短序列长度的权衡降低了模型训练的复杂性,同时不影响训练数据的完整性。
颜色名称长度的分布
在做出最大长度的艰难决定之后,字符级数据预处理的下一步是将每个颜色名称字符串转换为25个整数值列表,并且使用Keras文本标记化实用程序可以轻松实现。
from tensorflow.python.keras.preprocessing.text import Tokenizer
maxlen = 25
t = Tokenizer(char_level=True)
t.fit_on_texts(names)
tokenized = t.texts_to_sequences(names)
padded_names = preprocessing.sequence.pad_sequences(tokenized, maxlen=maxlen)
现在padded_names将具有(14157,25)的形状,其中14157是总训练样本数量,25是最大序列长度。如果一个字符串少于25个字符,将从序列的开头填充值0。
你可能会想,现在所有的输入都是整数形式,我们的模型应该能够处理它。但是,我们可以采取更多的步骤来使后面的模型训练更加有效。
One-hot encoding
我们可以通过检查Keras的Tokenizer实例的t.word_index属性来查看字符到整数映射。
{'':4,'a':2,'b':18,'c':11,'d':13,'e':1,'f':22,'g':14,'h ':16,'i':5,'j':26,'k':21,'l':7,'m':17,'n':6,'o':8,'p': 15,'q':25,'r':3,'s':10,'t':9,'u':12,'v':23,'w':20,'x':27, 'y':19,'z':24}
整数值在彼此之间没有自然的有序关系,我们的模型可能无法利用它的任何好处。更糟糕的是,我们的模型最初会假定这些字符之间存在这样的排序关系(即“a”是2,“e”是1,但不应该表示关系),这可能会导致不希望的结果。我们将使用One-hot编码来表示输入序列。
每个整数将由布尔数组表示,其中数组中只有一个元素的值为1.最大整数值将确定字符字典中布尔数组的长度。
在我们的例子中,最大整数值是'x':27,所以一个热点布尔数组的长度将是28(考虑最低值从0开始,即填充)。
例如,我们不是使用整数值2来表示字符'a',而是使用一个热门数组[0,0,1,0 ...... 0]。
Keras还提供One-hot编码。
from keras.utils import np_utils
one_hot_names = np_utils.to_categorical(padded_names)
生成的one_hot_names的形状(14157,25,28)表示(训练样本数,最大序列长度,唯一令牌数量)
数据标准化
请记住,我们预测3个颜色通道值,每个值在0-255之间。数据规范化没有黄金法则。数据归一化是纯粹实用的,因为在实践中,如果训练数据值散布过多,它可能会永远采用一个模型来收敛。常用的标准化技术是将值缩放到[-1,1]。在我们的模型中,我们在最后一层使用ReLu激活函数。由于ReLu输出非负数,我们将这些值归一化为[0,1]。
# The RGB values are between 0 - 255
# scale them to be between 0 - 1
def norm(value):
return value / 255.0
normalized_values = np.column_stack([norm(data["red"]), norm(data["green"]), norm(data["blue"])])
建立模型
为了建立我们的模型,我们将使用两种类型的神经网络,一个前馈神经网络和一个递归神经网络。前馈神经网络是迄今为止最常见的神经网络类型。在这个神经网络中,信息进入输入单元,并通过隐藏层向一个方向流动,直到每个输入单元都到达输出单元。
在循环神经网络中,信息可以循环流动。这些网络可以长时间记住信息。循环网络是模拟连续数据的一种非常自然的方式。在我们的具体模型中,我们使用了一种称为长期短期记忆(LSTM)的最强大的循环网络。
在Keras中构建深度学习模型的最简单方法是使用它的顺序API,并且我们只需通过调用它的model.add()函数(如连接乐高积木)来连接每个神经网络层。
from tensorflow.python.keras.models import Sequential
from tensorflow.python.keras.layers import Dense, Dropout, LSTM, Reshape
model = Sequential()
model.add(LSTM(256, return_sequences=True, input_shape=(maxlen, 28)))
model.add(LSTM(128))
model.add(Dense(128, activation='relu'))
model.add(Dense(3, activation='sigmoid'))
model.compile(optimizer='adam', loss='mse', metrics=['acc'])
通过调用model.fit()函数来训练模型不会更轻松。请注意,我们预留了10%的样本用于验证目的。如果事实证明模型在训练集上达到了很高的精度,但在验证集上低得多,那么模型可能是过度拟合的。
history = model.fit(one_hot_names, normalized_values,
epochs=40,
batch_size=32,
validation_split=0.1)
生成RGB颜色
让我们定义一些函数来生成并显示预测的颜色。
对于颜色名称输入,我们需要将其转换为one-hot 表示。为了达到这个目的,我们使用与我们处理训练数据相同的标记器将字符标记为整数,并将其填充到最大序列长度25,然后将单热编码应用于整数序列。
对于输出的RGB值,我们需要将其缩小回到0-255,所以我们可以正确显示它们。
# plot a color image
def plot_rgb(rgb):
data = [[rgb]]
plt.figure(figsize=(2,2))
plt.imshow(data, interpolation='nearest')
plt.show()
def scale(n):
return int(n * 255)
def predict(name):
name = name.lower()
tokenized = t.texts_to_sequences([name])
padded = preprocessing.sequence.pad_sequences(tokenized, maxlen=maxlen)
one_hot = np_utils.to_categorical(padded, num_classes=28)
pred = model.predict(np.array(one_hot))[0]
r, g, b = scale(pred[0]), scale(pred[1]), scale(pred[2])
print(name + ',', 'R,G,B:', r,g,b)
plot_rgb(pred)
让我们试一试predict()
predict("tensorflow orange")
predict("forest")
predict("keras red")
结论和进一步阅读
在这篇文章中,我们讨论了如何构建一个可以使用任何颜色名称并提供RGB颜色值的Keras模型。更具体地说,我们着眼于如何将one-hot编码应用于字符级语言模型,构建具有前馈神经网络和递归神经网络的神经网络模型。
下面是一个图表,总结了我们在帖子中构建的内容,从底部开始展示数据流的每一步。