针对这个问题,实际用到的非常频繁,比如用户画像,我爸爸的百度首页就和我妈妈的不一样,虽然他们在设置里都没填写个人信息,但是还是知道他们分别喜欢什么,这是怎么做到的呢?
通过浏览的新闻,大致描述出用户的收入年龄等,再由后台对新闻的 Tag 标签,推送可能更感兴趣的新闻。注意这里的性别分类和收入分类就是不同的,一个是二分类,一个是多分类,这也需要定义不同的损失函数。想要完成这种任务,在对模型进行编译的时候,进行定义就是很好的办法。这里要注意,不平衡的损失贡献会影响模型的训练,如果某一项损失值特别大时,会导致模型会先对其进行优化而较少考虑或几乎不考虑其他任务的优化,这不是我们想看到的,因此我们还可以定义不同的损失对最终损失贡献的大小,进行损失加权:
def run(): vocabulary_size = 50000 num_income_groups = 10 posts_input = Input(shape=(None,), dtype='int32',) embedded_posts = layers.Embedding(256, vocabulary_size)(posts_input) x = layers.Conv1D(128, 5, activation='relu')(embedded_posts) x = layers.MaxPooling1D(5)(x) x = layers.Conv1D(256, 5, activation='relu')(x) x = layers.Conv1D(256, 5, activation='relu')(x) x = layers.MaxPooling1D(5)(x) x = layers.Conv1D(256, 5, activation='relu')(x) x = layers.Conv1D(256, 5, activation='relu')(x) x = layers.GlobalMaxPooling1D()(x) x = layers.Dense(128, activation='relu')(x) age_prediction = layers.Dense(1,)(x) income_prediction = layers.Dense(num_income_groups, activation='softmax',)(x) gender_prediction = layers.Dense(1, activation='sigmoid',)(x) model = Model(posts_input, [age_prediction, income_prediction, gender_prediction]) model.summary() # 关键在这里 model.compile(optimizer='rmsprop', loss={'age': 'mse', 'income': 'categorical_crossentropy', 'gender': 'binary_crossentropy'}, loss_weights={'age': 0.25, 'income': 1., 'gender': 10.}) # model.fit(posts, [age_targets, income_targets, gender_targets], epochs=10, batch_size=64) 图结构当然,这里的图结构指的是有向无环图,层与层之间无环,层内部可以有环(循环神经网络),前文提到了,层就像函数,张量是输入也是输出,那么就可以由这些向量像搭积木一样组合复杂的网络图结构由上面多输入和多输出的例子,你应该也大致知道应该怎么组合了吧,这里给出两个非常著名的例子,如下:
Inception 模块本模块有助于学习空间特征和每个通道的特征,这比联合学习这两种特征更加有效。本模型内置在 keras.applications.inception_v3.InceptionV3 中,对于处理 ImageNet 数据集有很好的效率和准确度。
branch_a = layers.Conv2D(128, 1, activation='relu', strides=2)(x) branch_b = layers.Conv2D(128, 1, activation='relu')(x) branch_b = layers.Conv2D(128, 3, activation='relu', strides=2)(branch_b) branch_c = layers.AveragePooling2D(3, strides=2)(x) branch_c = layers.Conv2D(128, 3, activation='relu')(branch_c) branch_d = layers.Conv2D(128, 1, activation='relu')(x) branch_d = layers.Conv2D(128, 3, activation='relu')(branch_d) branch_d = layers.Conv2D(128, 3, activation='relu', strides=2)(branch_d) output = layers.concatenate([branch_a, branch_b, branch_c, branch_d], axis=-1) 残差连接本模块有助于解决梯度消失(反馈信号传递到更底部的层时,信号非常微弱)和表示瓶颈(某些层的参数过少,会导致某些特征永久消失,后面的层无法获取特征信息)的问题,具体的做法就是让前面某层的输出作为后面某层的输入: