Skip to content

Commit

Permalink
Create 2020-02-27-高级API之keras.md
Browse files Browse the repository at this point in the history
  • Loading branch information
YujunXie authored Feb 27, 2020
1 parent 6323a4a commit 3f026ad
Showing 1 changed file with 189 additions and 0 deletions.
189 changes: 189 additions & 0 deletions _posts/2020-02-27-高级API之keras.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
---
title: 高级的API之keras
key: 20200227
tags: 深度学习 Tensorflow

---

- [批数据训练](#批数据训练)
- [自定义DataGenerator](#自定义DataGenerator)
- [Sequential与Model模型](#Sequential与Model模型)
- [Layer](#Layer)
- [其他](#其他)

批数据训练
---
- train_on_batch(x, y, sample_weight=None, class_weight=None, reset_metrics=True)
与直接使用fit_generator对generator直接进行训练相比,当我们需要对输入数据进行修改时,或者有多个输入输出时,需要改变generator中的x,y。可以使用train_on_batch函数对每个batch的数据进行训练。

- test_on_batch(x, y, sample_weight=None, reset_metrics=True)
对应的,validation部分不参与训练,使用test_on_batch函数。

完整的train+val:同时含有如何在train_on_batch中调用tensorboard
```
def write_log(callback, names, logs, batch_no):
for name, value in zip(names, logs):
summary = tf.Summary()
summary_value = summary.value.add()
summary_value.simple_value = value
summary_value.tag = name
callback.writer.add_summary(summary, batch_no)
callback.writer.flush()
callback = TensorBoard(log_path)
callback.set_model(model)
for i in range(int(args.max_epoch)):
train_step = 0
for train_batch_data in train_generator:
if len(train_batch_data[0]) < args.batch_size:
continue
X_train, y_train = get_data(train_generator, ...)
metrics = model.train_on_batch(X_train, y_train)
write_log(callback, ['train_loss', 'train_acc', 'train_rc', 'train_pre'], metrics, train_step)
train_step += 1
if train_step >= args.step_train:
break
val_step = 0
for val_batch_data in val_generator:
if len(val_batch_data[0]) < args.batch_size:
continue
X_val, y_val = get_data(val_generator, ...)
val_out = model.test_on_batch(X_val, y_val)
val_step += 1
if val_step >= args.step_val:
break
write_log(callback, ['val_loss', 'val_acc', 'val_rc', 'val_pre'], result, i)
```
我们需要从train_generator/val_generator中读每个batch的数据。
我们设置batch_size变量来控制数据量,然而当训练样本总数不是batch_size的整数倍时,往往会多出一部分非batch_size数量的数据。
对于这份数据我们要么丢弃,要么补充到batch_size的个数。
我们知道generator是一种生成器,保存的是算法,每次调用next(),就计算出下一个元素的值,直到计算到最后一个元素。所以如果不加控制的读取,会陷入无尽的循环。
所以当使用for循环读取generator中的数据时,我们应该对以下两个条件进行判断:一个是当数据不满足batch_size时,丢掉这批数据。一个是设置一个epoch中的迭代次数,即训练次数,及时调出循环。

此外,使用zip函数也可以有效的对generator中的有效数据进行顺序封装,不需要判断迭代次数。但是在数据量较大时慎用,容易造成堵塞,导致程序被杀死。

自定义DataGenerator
---
[自定义DataGenerator](https://blog.csdn.net/ZWX2445205419/article/details/96109272)

Sequential与Model模型
---
- Sequential模型
**顺序式模型**
1. Layer提供input与output属性;
2. 第一个Layer必须是InputLayer或者Input函数构建的张量;

```
# 定义层
input_layer = keras.Input(shape=(4,)) # 输入层
hide1_layer = layers.Dense(units=8, activation='relu')
hide2_layer = layers.Dense(units=4, activation='relu')
output_layer = layers.Dense(units=1, activation='sigmoid')
# 建立模型
seq_model = keras.Sequential()
seq_model.add(input_layer)
seq_model.add(hide1_layer)
seq_model.add(hide2_layer)
seq_model.add(output_layer)
```

- Model模型
**函数式模型**,比Sequential模型复杂,但是效果很好,可以同时/分阶段输入变量,分阶段输出想要的模型。
1. 构建的Layer为可调用对象,提供__call__可调用运算符(...),或者使用apply与call实现链式函数调用;
2. Model只需要通过inputs与outputs;
```
# 定义层
input_layer = keras.Input(shape=(4,)) # 输入层
hide1_layer = layers.Dense(units=8, activation='relu')
hide2_layer = layers.Dense(units=4, activation='relu')
output_layer = layers.Dense(units=1, activation='sigmoid')
# 调用
hide1_layer_tensor = hide1_layer(input_layer)
hide2_layer_tensor = hide2_layer(hide1_layer_tensor)
output_layer_tensor = output_layer(hide2_layer_tensor)
# 建立模型
model = keras.Model(inputs=input_layer, outputs=output_layer_tensor)
```
- 定制模型

Layer
---
- 自定义层
Keras是一个高度封装的库,它的优点是可以进行快速的建模,缺点是它不处理**底层运算**,如张量内积等。为了弥补这个问题,Keras提供“Backend”来实现底层运算操作。目前Keras支持的后端引擎有tensorflow,CNTK,Theano。默认的是使用tensorflow,你可以在.keras/keras.json文件中更改backend。我们可以使用keras提供的后端来实现任意你想实现的layer。

```
from keras import backend as K
from keras.layers import Layer
class MyLayer(Layer):
def __init__(self, output_dim, **kwargs):
self.output_dim = output_dim
super(MyLayer, self).__init__(**kwargs)
def build(self, input_shape):
# Create a trainable weight variable for this layer.
self.kernel = self.add_weight(name='kernel',
shape=(input_shape[1], self.output_dim), initializer='uniform', trainable=True)
super(MyLayer, self).build(input_shape) # Be sure to call this at the end
def call(self, x):
return K.dot(x, self.kernel)
def compute_output_shape(self, input_shape):
return (input_shape[0], self.output_dim)
```

- Lambda层
Keras的最小操作单位是Layer,每次操作的是整个batch。Backend中Tensorflow的最小操作单位是Tensor,每次操作的数据是batch中的所有数据。而对于每个batch中的tensor的一些backend操作需要使用Lambda层进行封装。
```
a = Input(shape=(2,))
b = Input(shape=(2,))
def minus(inputs):
x, y = inputs
return K.mean(x - y, axis=1)
m = Lambda(minus, name='minus')([a, b])
model = Model(inputs=[a, b], outputs=[m])
```

其他
---
- map_fn高阶函数
```
tf.keras.backend.map_fn(
fn,
elems,
name=None,
dtype=None
)
```
将函数fn映射到元素elems并返回输出。
其中fn是一个可调用函数,可以使用 lambda 来表示,elems 是需要处理的 tensors, tf 将会从第一维开始展开,进行 map 操作,dtype 表示 fn 函数的输出类型,如果 fn 返回的类型和 elems 中的不同,那么就必须显示指定为和 fn 返回类型相同的类型。
当各个batch之间没有关联时,可以并行高效处理每个batch中的数据,是一个batch-wise操作。

- tf.gather
用一个一维的索引数组,将tensor中对应index的向量提取出来。(不连续索引)
tf.gather_nd允许在多维上进行索引。
[tf.gather](https://github.com/tensorflow/docs/blob/r1.11/site/en/api_docs/python/tf/gather.md)

- 使用one_hot进行加减运算
tf.one_hot(indices, depth, dtype)
indices表示输入的多个数值,通常是矩阵形式;depth表示输出的尺寸。由于one-hot类型数据长度为depth位,其中只用一位数字表示原输入数据,这里的on_value就是这个数字,默认值为1,one-hot数据的其他位用off_value表示,默认值为0。
indices = 0 对应的输出是[1, 0 … 0, 0], indices = 1 对应的输出是[0, 1 … 0, 0], 依次类推,最大可能值的输出是[0, 0 … 0, 1]

Tensorflow中是不能直接修改tensor的数值的,使用one_hot函数巧妙进行加减运算。下面操作是将1536维tensro中对应非indice中索引的数值赋0:
```
# inputs.shape(1536,) indices.shape(512,)
one_hot = tf.one_hot(indices, 1536, dtype=tf.float32)
one_hot = tf.reshape(one_hot, (1536, -1))
one_hot = K.max(one_hot, axis=1, keepdims=False)
x = K.identity(inputs) + one_hot * inputs
```

---
参考文献:
[Keras Documentation](https://keras.io/)
[A detailed example of how to use data generators with Keras](https://stanford.edu/~shervine/blog/keras-how-to-generate-data-on-the-fly)
[Keras的Model模型使用](https://www.jianshu.com/p/c0d6a0c61984)

0 comments on commit 3f026ad

Please sign in to comment.