keras函数式编程(多任务学习,共享网络层)
https://keras.io/zh/
https://keras.io/zh/getting-started/functional-api-guide/
https://github.com/keras-team/keras/tree/master/examples
Keras 函数式 API 是定义复杂模型(如多输出模型、有向无环图,或具有共享层的模型)的方法。 函数式API: https://keras.io/zh/models/model/
- 网络层的实例是可调用的,它以张量为参数,并且返回一个张量
- 输入和输出均为张量,它们都可以用来定义一个模型(
Model) - 这样的模型同 Keras 的
Sequential模型一样,都可以被训练
from keras.layers import Input, Dense
from keras.models import Model # 这部分返回一个张量
inputs = Input(shape=(784,)) # 层的实例是可调用的,它以张量为参数,并且返回一个张量
x = Dense(64, activation='relu')(inputs)
x = Dense(64, activation='relu')(x)
predictions = Dense(10, activation='softmax')(x) # 这部分创建了一个包含输入层和三个全连接层的模型
model = Model(inputs=inputs, outputs=predictions)
model.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
model.fit(data, labels) # 开始训练
函数式API用途一:多输入多输出模型(多任务学习MTL)
预测 Twitter 上的一条新闻标题有多少转发和点赞数。模型的主要输入将是新闻标题本身,即一系列词语,同时还添加了其他的辅助输入来接收额外的数据,例如新闻标题的发布的时间等。 该模型也将通过两个损失函数进行监督学习。
模型结构:
=> 通过函数式API实现该模型。
主要输入接收新闻标题本身,即一个整数序列(每个整数编码一个词)。 这些整数在 1 到 10,000 之间(10,000 个词的词汇表),且序列长度为 100 个词。
from keras.layers import Input, Embedding, LSTM, Dense
from keras.models import Model # 标题输入:接收一个含有 100 个整数的序列,每个整数在 1 到 10000 之间。
# 注意我们可以通过传递一个 "name" 参数来命名任何层。
main_input = Input(shape=(100,), dtype='int32', name='main_input') # Embedding 层将输入序列编码为一个稠密向量的序列,
# 每个向量维度为 512。 x为向量序列,100个向量,每个向量维度为512
x = Embedding(output_dim=512, input_dim=10000, input_length=100)(main_input) # LSTM 层把向量序列转换成单个向量,输出32维向量
# 它包含整个序列的上下文信息
lstm_out = LSTM(32)(x)
插入辅助损失,使得即使在模型主损失很高的情况下,LSTM 层和 Embedding 层都能被平稳地训练:
auxiliary_output = Dense(1, activation='sigmoid', name='aux_output')(lstm_out)
将辅助输入数据与 LSTM 层的输出连接起来,输入到模型中:
auxiliary_input = Input(shape=(5,), name='aux_input')
x = keras.layers.concatenate([lstm_out, auxiliary_input]) # 这里是如何连接的? 行向量与列向量。后续可以输出测试数据看一下 # 堆叠多个全连接网络层
x = Dense(64, activation='relu')(x)
x = Dense(64, activation='relu')(x)
x = Dense(64, activation='relu')(x) # 最后添加主要的逻辑回归层
main_output = Dense(1, activation='sigmoid', name='main_output')(x)
定义一个具有两个输入和两个输出的模型:
model = Model(inputs=[main_input, auxiliary_input], outputs=[main_output, auxiliary_output])
编译模型,并给辅助损失分配一个 0.2 的权重。如果要为不同的输出指定不同的 loss_weights或 loss,可以使用列表或字典。 在这里,我们给 loss 参数传递单个损失函数,这个损失将用于所有的输出:
model.compile(optimizer='rmsprop',
loss={'main_output': 'binary_crossentropy', 'aux_output': 'binary_crossentropy'},
loss_weights={'main_output': 1., 'aux_output': 0.2}) # 然后使用以下方式训练:
model.fit({'main_input': headline_data, 'aux_input': additional_data},
{'main_output': labels, 'aux_output': labels},
epochs=50, batch_size=32)
辅助损失函数反向传播:
(多任务学习中)辅助损失函数记为loss_0,主损失函数记为loss_1, 有两种反向传播方法:1、用loss=loss_0+loss_1,然后再梯度反传; 2、分别loss_0和loss_1去反向传播; 一般情况下会设置两个loss的比例,作为一个超参数进行调整,上述直接相加就相当于1:1。如果两个loss分别训练, 就是给问题两个优化目标, 如果两个loss的优化方向有差别, 可能导致优化结果波动,难以收敛。
函数式API用途二:共享网络层
建立一个模型来分辨两条推文是否来自同一个人(例如,通过推文的相似性来对用户进行比较)。实现这个目标的一种方法是建立一个模型,将两条推文编码成两个向量,连接向量,然后添加逻辑回归层;这将输出两条推文来自同一作者的概率。模型将接收一对对正负表示的推特数据。
由于这个问题是对称的,编码第一条推文的机制应该被完全重用来编码第二条推文(权重及其他全部)。这里我们使用一个共享的 LSTM 层来编码推文。
首先我们将一条推特转换为一个尺寸为 (280, 256) 的矩阵,即每条推特 280 字符,每个字符为 256 维的 one-hot 编码向量 (取 256 个常用字符)。
import keras
from keras.layers import Input, LSTM, Dense
from keras.models import Model tweet_a = Input(shape=(280, 256))
tweet_b = Input(shape=(280, 256))
要在不同的输入上共享同一个层,只需实例化该层一次,然后根据需要传入你想要的输入即可:
# 这一层可以输入一个矩阵,并返回一个 64 维的向量
shared_lstm = LSTM(64) # 当我们重用相同的图层实例多次,图层的权重也会被重用 (它其实就是同一层)
encoded_a = shared_lstm(tweet_a)
encoded_b = shared_lstm(tweet_b) # 然后再连接两个向量:
merged_vector = keras.layers.concatenate([encoded_a, encoded_b], axis=-1) # 再在上面添加一个逻辑回归层
predictions = Dense(1, activation='sigmoid')(merged_vector) # 定义一个连接推特输入和预测的可训练的模型
model = Model(inputs=[tweet_a, tweet_b], outputs=predictions) model.compile(optimizer='rmsprop',
loss='binary_crossentropy',
metrics=['accuracy'])
model.fit([data_a, data_b], labels, epochs=10)
层(节点)的概念 : 获取多输入layer的输出
每当你在某个输入上调用一个层时,都将创建一个新的张量(层的输出),并且为该层添加一个「节点」,将输入张量连接到输出张量。当多次调用同一个图层时,该图层将拥有多个节点索引 (0, 1, 2...)。
在之前版本的 Keras 中,可以通过 layer.get_output() 来获得层实例的输出张量,或者通过 layer.output_shape 来获取其输出形状。现在你依然可以这么做(除了 get_output() 已经被 output 属性替代)。但是如果一个层与多个输入连接呢?
只要一个层仅仅连接到一个输入,就不会有困惑,.output 会返回层的唯一输出:
a = Input(shape=(280, 256)) lstm = LSTM(32)
encoded_a = lstm(a) assert lstm.output == encoded_a
但是如果该层有多个输入,那就会出现问题:
a = Input(shape=(280, 256))
b = Input(shape=(280, 256)) lstm = LSTM(32)
encoded_a = lstm(a)
encoded_b = lstm(b) lstm.output
>> AttributeError: Layer lstm_1 has multiple inbound nodes,
hence the notion of "layer output" is ill-defined.
Use `get_output_at(node_index)` instead.
通过下面的方法可以解决:
assert lstm.get_output_at(0) == encoded_a
assert lstm.get_output_at(1) == encoded_b
input_shape 和 output_shape 这两个属性也是如此:只要该层只有一个节点,或者只要所有节点具有相同的输入/输出尺寸,那么「层输出/输入尺寸」的概念就被很好地定义,并且将由 layer.output_shape / layer.input_shape 返回。但是比如说,如果将一个 Conv2D 层先应用于尺寸为 (32,32,3) 的输入,再应用于尺寸为 (64, 64, 3) 的输入,那么这个层就会有多个输入/输出尺寸,你将不得不通过指定它们所属节点的索引来获取它们:
a = Input(shape=(32, 32, 3))
b = Input(shape=(64, 64, 3)) conv = Conv2D(16, (3, 3), padding='same')
conved_a = conv(a) # 到目前为止只有一个输入,以下可行:
assert conv.input_shape == (None, 32, 32, 3) conved_b = conv(b)
# 现在 `.input_shape` 属性不可行,但是这样可以:
assert conv.get_input_shape_at(0) == (None, 32, 32, 3)
assert conv.get_input_shape_at(1) == (None, 64, 64, 3)
更多的一些例子:
inception模型、残差网络、共享视觉模型、视觉问答模型等
keras函数式编程(多任务学习,共享网络层)的更多相关文章
- Python函数式编程初级学习
函数式编程即函数可以作为参数传入函数,也可以返回函数. 1.高阶函数 函数可以作为参数传入函数. def add(x,y,f): return f(x)+f(y) ...
- python函数式编程之高阶函数学习
基本概念 函数式编程,是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量.因此,任意一个函数,只要输入确定,输出就确定的这种函数我们称之为纯函数,我们称这种函数没有副作用.而允许使用 ...
- 转: JavaScript函数式编程(二)
转: JavaScript函数式编程(二) 作者: Stark伟 上一篇文章里我们提到了纯函数的概念,所谓的纯函数就是,对于相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用,也不依赖外部环 ...
- 翻译连载 |《你不知道的JS》姊妹篇 |《JavaScript 轻量级函数式编程》- 引言&前言
原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS>作者 译者团队(排名不分先后):阿希.blueken.brucec ...
- Java8新特性:函数式编程
1. 概述 函数式编程学习目的: 能够看懂公司里的代码 大数据量下处理集合效率更高 代码可读性高 消灭嵌套地狱 函数式编程思想: 面向对象思想需要关注用什么对象完成什么事情.而函数式编程思想就类似于我 ...
- Haskell学习-函数式编程初探
原文地址:Haskell学习-函数式编程初探 为什么要学习函数式编程?为什么要学习Haskell? .net到前端,C#和JavaScript对我来说如果谈不上精通,最起码也算是到了非常熟悉的 ...
- Scala学习教程笔记三之函数式编程、集合操作、模式匹配、类型参数、隐式转换、Actor、
1:Scala和Java的对比: 1.1:Scala中的函数是Java中完全没有的概念.因为Java是完全面向对象的编程语言,没有任何面向过程编程语言的特性,因此Java中的一等公民是类和对象,而且只 ...
- JavaScript学习(3):函数式编程
在这篇文章里,我们讨论函数式编程. 什么是函数式编程?根据百度百科的描述,“函数式编程是种编程典范,它将电脑运算视为函数的计算.函数编程语言最重要的基础是 λ 演算(lambda calculus). ...
- boost 的函数式编程库 Phoenix入门学习
这篇文章是我学习boost phoenix的总结. 序言 Phoenix是一个C++的函数式编程(function programming)库.Phoenix的函数式编程是构建在函数对象上的.因此,了 ...
随机推荐
- (51)zabbix命令:zabbix_get获取item数据
zabbix_get是什么?有什么作用? 总有人在群里提问,为什么zabbix获取不到数据,为什么zabbix提示Not Support,怎么办?别老问,用zabbix_get试着获取数据即可.在za ...
- modprode
modprobe命令 1.modprobe 命令是根据depmod -a的输出/lib/modules/version/modules.dep来加载全部的所需要模块. 2.删除模块的命令是:modpr ...
- redis 散列学习要点记录
散列类型键值也是种字典结构,存储了字段和字段值的映射,字段值只能是字符串,不可以是其他类型(redis数据类型都不可嵌套使用其他类型),散列类型键可以有2的32次方减1个字段 散列的命令组 hset ...
- Python Importlib模块与__import__详解
Importlib模块与__import__都可以通过过字符串来导入另外一个模块,但在用法上和本质上都有很大的不同. 以一个例子为证: 以下为我的工程目录结构: lib/test.py: name = ...
- spring cloud 学习资源
1.https://blog.csdn.net/column/details/17737.html 2.https://blog.csdn.net/column/details/15197.html? ...
- 三丶人生苦短,我用python【第三篇】 pycharm
1 pycharm的下载安装 下载地址:https://www.jetbrains.com/pycharm/download/#section=windows ....安装没啥好说的 建议购买正版,其 ...
- 大数据学习——Storm学习单词计数案例
需求:计算单词在文档中出现的次数,每出现一次就累加一次 遇到的问题 这个问题是<scope>provided</scope>作用域问题 https://www.cnblogs. ...
- .NET重构(八):周结账单中,给报表添加参数
导读:进行完了日结报表的制作,大松一口气.不过,刚开始看着周结账单中的两个参数问题,也是愁了很久.不过,只要思想不滑坡,办法总比困难多.接下来,就写写我制作周结账单报表的过程. 一.添加参数 1,在日 ...
- 九度oj 题目1369:字符串的排列
题目描述: 输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba. 输入: 每个 ...
- Android Email check 正则表达式
Android Email check 正则表达式 (?:[-!#-\\'*+\\x2f-9=?A-Z^-~]+(?:\\.[-!#-\\'*+\\x2f-9=?A-Z^-~]+)*|\"( ...