我们试想一个实际问题,春天到了,我们要买衣服了,同时,作为服装厂商,也要开始发布新的衣服了,如果你作为一个服装厂商的技术顾问,请你分析出什么样的衣服属于今年的流行趋势,你会怎么做?
首先,作为技术宅男的你,我不认为你会对流行元素有那么多的关注,不会去看什么巴黎时装周,你能做的就是根据各种各样的数据进行分析预测。你可能会在店铺中进行一些扫码填写调查表发放一些优惠券,还可能去各大时尚网站去扒一些评论分析文章,还可能去微博这种公开的社交平台扒一些时尚博主的自拍分享等,你可以想尽办法获取各种各样的数据,你要做的是用好这些数据分析出流行趋势。
对于这种分析预测深度学习无疑是适合的模型工具,问题是既有这种调查表得来的数据,适合普通的层堆叠进行训练的模型,还有这种评论分析文章这种文本数据,适合循环神经网络的文章,还有各种图片需要分析,适合卷积神经网络的模型,这可怎么办?根据我们现有的知识,我们可以考虑分别训练不同的网络模型,对他们进行加权分析,这固然是一种方法,但是这个权也太随机了,各个数据之间也都割裂开了,分别处理算不上好的方法。那怎么办?
将他们联合起来,进行联合学习,大致的样子就是这样:
当然,联合模型不只能同时接收多种输入,还可以同时给出输出,比如流行的元素和价格,多个输入多个输出,这就不单纯是一个前面我们提到的各种线性的网络,更像是一个图的感觉,对,就是那种类似于数据结构中的图。就像数据结构中的图要比线性链表复杂得多一样,深度学习中的这种联合模型也比单一的一种模型要复杂得多。
函数式 API这是预备知识,所谓函数式方式,很幸运 Keras 支持这样的方式,就是把层看成函数,这个函数的参数和返回值都是张量,这样的函数组合起来就能构成网络模型,看下面的代码例子:
def run(): # 我们学过的用 Sequential 定义层 seq_model = Sequential() seq_model.add(layers.Dense(32, activation='relu', input_shape=(64,))) seq_model.add(layers.Dense(32, activation='relu')) seq_model.add(layers.Dense(10, activation='softmax')) seq_model.summary() # 用函数的方式定义层 input_tensor = Input(shape=(64,)) x = layers.Dense(32, activation='relu')(input_tensor) x = layers.Dense(32, activation='relu')(x) output_tensor = layers.Dense(10, activation='softmax')(x) model = Model(input_tensor, output_tensor) model.summary()这两种定义网络模型的方式是等价的,Input 是用来定义张量的,原始数据可以转换成张量用于网络训练,Model 是用来找到从 input_tensor 到 output_tensor 的路径,将其加入到网络中。
多输入模型假设一个模型在进行一个简化版的图灵测试,这个模型要回答一个问题,这个问题的答案放在一篇文章中也由这个模型去处理,那么这个模型就是拥有多个输入的一个网络,如下:
其中有许多的知识我们之前讨论过了,如 LSTM 是循环神经网络,用于处理文本。这里的 Concatenate 需要解释一下:Concatenate 用于连接,可以将输入的问题和答案文本相关联起来。用代码构建的网络进行 summary 查看是这个样子的:
#!/usr/bin/env python3 import time import keras import numpy as np from keras import Input from keras import layers from keras.models import Model def run(): text_vocabulary_size = 10000 question_vocabulary_size = 10000 answer_vocabulary_size = 500 # 文本输入 text_input = Input(shape=(None,), dtype='int32',) # 将输入转换为向量 embedded_text = layers.Embedding(text_vocabulary_size, 64)(text_input) # 将输入转换为单个向量 encoded_text = layers.LSTM(32)(embedded_text) # 对问题进行如上处理 question_input = Input(shape=(None,), dtype='int32',) embedded_question = layers.Embedding(question_vocabulary_size, 32)(question_input) encoded_question = layers.LSTM(16)(embedded_question) # 将问题和文本联系起来 concatenated = layers.concatenate([encoded_text, encoded_question], axis=-1) # 添加一个 softmax 分类器 answer = layers.Dense(answer_vocabulary_size, activation='softmax')(concatenated) # 构建模型 model = Model([text_input, question_input], answer) model.summary() model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['acc']) # 生成虚拟训练数据,参考意义不大 num_samples = 1000 max_length = 100 text = np.random.randint(1, text_vocabulary_size, size=(num_samples, max_length)) question = np.random.randint(1, question_vocabulary_size, size=(num_samples, max_length)) answers = np.random.randint(answer_vocabulary_size, size=(num_samples)) answers = keras.utils.to_categorical(answers, answer_vocabulary_size) model.fit([text, question], answers, epochs=10, batch_size=128) model.fit({'text': text, 'question': question}, answers, epochs=10, batch_size=128) if __name__ == "__main__": time_start = time.time() run() time_end = time.time() print('Time Used: ', time_end - time_start) 多输出模型