上篇文章自定义 metrics 用到了 add_weights 方法,这个方法会初始化一个变量,维度不定。参数初始化的选择,对后续的模型迭代效果与收敛速度都有一定影响。下面看下 Keras 有哪些常见的初始化方法:
自定义 metrics 用到的 add_weight 并调用 initializer 初始化函数:
class CategoricalTruePositives(keras.metrics.Metric):
def __init__(self, name="categorical_true_positives", **kwargs):
super(CategoricalTruePositives, self).__init__(name=name, **kwargs)
self.true_positives = self.add_weight(name="ctp", initializer="zeros")
# 也可以调整shape一次计算多个指标
self.b = self.add_weight(name="b",initializer="random_uniform")
常见的 keras 参数初始化方法:
初始化方法 | 参数 |
正态化的Glorot初始化 | glorot_normal |
标准化的Glorot初始化 | glorot_uniform |
正态化的he初始化 | he_normal |
标准化的he初始化 | he_uniform |
正态化的lecun初始化 | lecun_normal |
标准化的lecun初始化 | lecun_uniform |
截断正态分布 | truncated_normal |
标准正态分布 | random_normal |
均匀分布 | random_uniform |
首先编写一个简单模型,并初始化其参数,然后 get_weights 并 plot 查看初始化参数的分布,这里接受 initial 参数并传给参数初始化,可以把上述常见初始化方法直接传入函数即可。这里 Dense 层 kernel 参数共有 50000 x 100 = 5000000 个:
def getDenseWeights(initial):
inputs = layers.Input(shape=(100,), name='input')
d1 = layers.Dense(50000, activation='sigmoid', name='dense1',kernel_initializer=initial)(inputs)
output = layers.Dense(7, activation='sigmoid', name='output')(d1)
model = keras.Model(inputs=inputs, outputs=output)
# 100 x 500
w_dense1 = np.array(model.get_layer('dense1').get_weights()[0]).reshape(-1) # 获取dense1层的参数
n, bins, patches = plt.hist(w_dense1,bins=1000)
plt.title(initial)
plt.xlabel('data range')
plt.ylabel('probability')
plt.show()
直接输入上述初始化方法名称即可:
getDenseWeights("glorot_normal")
keras.initializers.glorot_normal(seed=None)
Glorot 正态分布初始化器,也称为 Xavier 正态分布初始化器。
它从以 0 为中心,标准差为 stddev = sqrt(2 / (fan_in + fan_out))
的截断正态分布中抽取样本, 其中 fan_in
是权
值张量中的输入单位的数量, fan_out
是权值张量中的输出单位的数量。
keras.initializers.glorot_uniform(seed=None)
Glorot 均匀分布初始化器,也称为 Xavier 均匀分布初始化器。
它从 [-limit,limit] 中的均匀分布中抽取样本, 其中 limit
是 sqrt(6 / (fan_in + fan_out))
, fan_in
是权值张量中的
输入单位的数量, fan_out
是权值张量中的输出单位的数量。
keras.initializers.he_normal(seed=None)
He 正态分布初始化器。
它从以 0 为中心,标准差为 stddev = sqrt(2 / fan_in)
的截断正态分布中抽取样本, 其中 fan_in
是权值张量中的输入
单位的数量。
keras.initializers.he_uniform(seed=None)
He 均匀方差缩放初始化器。
它从 [-limit,limit] 中的均匀分布中抽取样本, 其中 limit
是 sqrt(6 / fan_in)
, 其中 fan_in
是权值张量中的输入单位的
数量。
keras.initializers.lecun_normal(seed=None)
LeCun 正态分布初始化器。
它从以 0 为中心,标准差为 stddev = sqrt(1 / fan_in)
的截断正态分布中抽取样本, 其中 fan_in
是权值张量中的输入
单位的数量。
keras.initializers.lecun_uniform(seed=None)
LeCun 均匀初始化器。
它从 [-limit,limit] 中的均匀分布中抽取样本, 其中 limit
是 sqrt(3 / fan_in)
, fan_in
是权值张量中的输入单位的数
量。
keras.initializers.TruncatedNormal(mean=0.0, stddev=0.05, seed=None)
这个初始化方法是 tensorflow 的默认初始化方法,按照截尾正态分布生成随机张量的初始化器。
生成的随机值与 RandomNormal
生成的类似,但是在距离平均值两个标准差之外的随机值将被丢弃并重新生成。这是用来生成
神经网络权重和滤波器的推荐初始化器。
参数
keras.initializers.RandomNormal(mean=0.0, stddev=0.05, seed=None)
标准正太分布,这个都比较熟悉了。
参数
keras.initializers.RandomUniform(minval=-0.05, maxval=0.05, seed=None)
参数
上面展示的初始化方法都使用了默认的函数名传入,无法控制 mean, std, limit 等参数,如果想要输入非默认的参数,可以采用如下形式,以 mean = 5 ,std = 3 的标准正态分布为例:
init = keras.initializers.RandomNormal(mean=5, stddev=3, seed=None)
def getDenseWeights(init):
inputs = layers.Input(shape=(100,), name='input')
d1 = layers.Dense(50000, activation='sigmoid', name='dense1',kernel_initializer=init)(inputs)
output = layers.Dense(7, activation='sigmoid', name='output')(d1)
model = keras.Model(inputs=inputs, outputs=output)
参数换成对应的 initializers
除了使用Api给出的方法外,也可以调用其他方法,自定义参数。自定义参数需要遵循如下条件,如果传递一个自定义的可调用函数,那么它必须使用参数 shape
(需要初始化的变量的尺寸)和 dtype
(数据类型):
def api_init(shape, dtype=None):
return K.random_normal(shape, dtype=dtype)
把 api_init 传给 getDenseWeights 即可。
有 50000 x 100 共 5000000 个参数,我比较任性,就想传 0 - 4999999 作为初始化参数怎么办:
def my_init(shape,dtype=None):
num = np.prod(shape)
arr = np.array(range(0,num))
return arr.reshape(shape)
同理,传给 getDenseWeights :
def getDenseWeights(initial):
inputs = layers.Input(shape=(100,), name='input')
d1 = layers.Dense(50000, activation='sigmoid', name='dense1',kernel_initializer=my_init)(inputs)
output = layers.Dense(7, activation='sigmoid', name='output')(d1)
model = keras.Model(inputs=inputs, outputs=output)
# 100 x 500
w_dense1 = np.array(model.get_layer('dense1').get_weights()[0]).reshape(-1) # 获取dense1层的参数
plt.plot(np.array(range(0,5000000)),w_dense1)
plt.title(initial)
plt.savefig("hist/{}".format(initial))
plt.show()
getDenseWeights("my_init")
这里就不画分布图了,只是演示一下怎么 diy ,如果想复用训练好的参数,在构建模型的时候,也可以调用 layer 的 set_weight 方法初始化参数,这里就不多赘述了。
参数初始化还有很多生成方法与生成方式,这里并不代表全部,更多初始化方法可以查看参数初始化-keras中文文档。