一般情况下,利用Keras建立模型,会使用线性模型(Sequential),但是在一些特殊情况下,我们或许会有多个input,这样的话,我们就不会使用线性模型,而使用Keras的Model。
from keras.models import Sequential # 线性模型,我们这次不使用这种
from keras.models import Model # Model可以用来处理多输入和多输出
假设我们需要训练这样一个简单的模型:
y = x1 + x2
其中输入为x1和x2,输出为y。我们使用一个for循环生成我们需要的数据,生成结束后我们对数据进行打乱处理,因为默认的方法在分离训练集和验证集的时候并不会打乱顺序,如果我们仅仅在数据的前80%进行训练,那后20%模型是无法学习到任何东西的。
def load_data(data_size = 100):
x1 = np.zeros(data_size)
x2 = np.zeros(data_size)
for i in range(data_size):
x1[i] = i
x2[i] = i
y = x1 + x2
index = np.arange(data_size)
np.random.shuffle(index)
x1 = x1[index] #使用相同的index,shuffle之后的关系依然是对应的
x2 = x2[index]
y = y[index]
return x1,x2,y
接下来我们构建一个简单的模型。简单的使用几层全连层就完成了架构。对Input进行命名不是必须的,但是会比较直观。和线性模型不同的是,我们必须定义每一层的输入和输出,这样才能找到每一层的对应关系。concatenate层链接了x1和x2的输出层,具有合并的作用。最后在定义模型输入的时候,使用数组作为模型的多个输入。
def load_model(x1,x2):
x1in = Input(shape = x1[0].shape, name='in1')
x2in = Input(shape = x2[0].shape, name='in2')
x1out = Dense(256, activation='relu')(x1in)
x1out = Dense(256, activation='relu')(x1out)
x2out = Dense(256, activation='relu')(x2in)
x2out = Dense(256, activation='relu')(x2out)
out = concatenate([x1out, x2out]) #链接层
out = Dense(256, activation='relu')(out)
out = Dense(1)(out)
model = Model(inputs=[x1in,x2in], outputs=out) #使用数组作为inputs
model.compile(optimizer='rmsprop', loss='mse', metrics=['mae'])
return model
定义完模型之后就可以开始训练了。我们同时定义了一个学习率改变器,每100个epoch会下降一下学习率,具体的运作原理不在本文讨论之内,目的只是让这个模型跑的效果更好。
def step_decay(epoch):
initial_lrate = 0.001
drop = 0.1
epochs_drop = 100.0
lrate = initial_lrate * math.pow(drop, math.floor((1+epoch)/epochs_drop))
return lrate
def train_model():
x1,x2,y = load_data()
x1 = x1.reshape(x1.shape[0], -1) #把数据reshape成模型可以读取的shape
x2 = x2.reshape(x2.shape[0], -1)
model = load_model(x1, x2)
model.summary()
reduce_lr = LearningRateScheduler(step_decay) #改变学习率
model.fit([x1,x2], y, epochs=1000, validation_split=0.2, batch_size=10, callbacks=[reduce_lr])
model.save('linear.model')
def main():
train_model()
来看一下模型的结构:
__________________________________________________________________________________________________
Layer (type) Output Shape Param # Connected to
==================================================================================================
in1 (InputLayer) (None, 1) 0
__________________________________________________________________________________________________
in2 (InputLayer) (None, 1) 0
__________________________________________________________________________________________________
dense_1 (Dense) (None, 256) 512 in1[0][0]
__________________________________________________________________________________________________
dense_3 (Dense) (None, 256) 512 in2[0][0]
__________________________________________________________________________________________________
dense_2 (Dense) (None, 256) 65792 dense_1[0][0]
__________________________________________________________________________________________________
dense_4 (Dense) (None, 256) 65792 dense_3[0][0]
__________________________________________________________________________________________________
concatenate_1 (Concatenate) (None, 512) 0 dense_2[0][0]
dense_4[0][0]
__________________________________________________________________________________________________
dense_5 (Dense) (None, 256) 131328 concatenate_1[0][0]
__________________________________________________________________________________________________
dense_6 (Dense) (None, 1) 257 dense_5[0][0]
==================================================================================================
Total params: 264,193
Trainable params: 264,193
Non-trainable params: 0
__________________________________________________________________________________________________
再来看一下训练的结果:
Epoch 1000/1000
80/80 [==============================] - 0s 308us/step - loss: 4.2059e-06 - mae: 0.0017 - val_loss: 4.2603e-06 - val_mae: 0.0018
发现结果非常准确,验证集的loss也非常低。
以上就是Keras多输入模型的例子了,同样Keras也支持多输出,一样举一反三。