Geoffrey Hinton在2015年写了一篇文章:
Hinton, G., Vinyals, O., & Dean, J. (2015). Distilling the knowledge in a neural network.
简介
这篇文章讲的是dark knowledge的应用,有两个:模型压缩、特殊网络的学习。
模型压缩部分,讲了用soft target训练小模型,可以让小模型有媲美大模型的表现。
特殊网络(specialist network)部分没认真看,不讨论。
Dark Knowledge思想
假设有一个图片识别的网络,输入一只猫,那么“狗”这个输出的softmax值一定比“船”高很多。
这个信息就是所谓的dark knowledge(个人理解)。
softmax函数的定义:q(i) = exp(z(i) / T) / ∑(exp(z(j) / T))
T是温度参数,一般取T = 1,这时就相当于求这个输出节点的exp值在所有输出中占的比重。显然
- T→+∞时,q(i)→1/N,其中N是输出节点的总数
- T→+0时,q(i)→[i == argmax(z(j))]。
显然,T越大,输出就越“均匀”,这种变得均匀了的输出就叫做soft target。
所谓的hard target,就是[0 1 0 0]这种one-hot label。
而soft target,就是[0.1 0.89 0.09 1e-6]这种,例如这个target对应一张猫的图片,那么第一个值就可能是狗,第二个就是猫,第三个可能是马什么的,第四个可能是船。体现了这些东西之间的关联性。
hard target很常见了,那么怎么搞出soft target呢?显然不能人工去搞,但我们可以训练一个网络,取一个合适的T值,把模型的输出当成soft target。
我这次实现的是论文中的“simplest form of knowledge distillation”。
实操
为了方便,直接使用 https://www.tensorflow.org/tutorials/ 上面的MNIST示例代码中的网络结构,但是要用函数式layer的方式来写。
这是一个朴素的全连接网络,包含一个隐含层,效果还算可以。为了测试,我们先把隐含层的节点数从512个改为64个,看一下准确率,大概是96.3%~96.4%。保持示例代码中隐含层512个节点不变的话,准确率大概98.5%。
接下来我们用512节点的模型的输出当做soft target训练64节点的网络。
import tensorflow as tf
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
inputs = tf.keras.layers.Input(shape=(28, 28))
flat = tf.keras.layers.Flatten()(inputs)
conv = tf.keras.layers.Dense(512, activation=tf.nn.relu)(flat)
dr = tf.keras.layers.Dropout(0.2)(conv)
fin = tf.keras.layers.Dense(10)(dr)
outputs = tf.keras.layers.Softmax()(fin)
这个网络的outputs就是一个T = 1的softmax;为了获得soft target,再写两个layer:
soft = tf.keras.layers.Lambda(lambda x: x / 4)(fin)
soft_o = tf.keras.layers.Softmax()(soft)
这里我们取温度T = 4,这个数值应该还有优化的余地。
接下来训练网络,暴力拿到soft target:
model = tf.keras.Model(inputs, outputs)
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.fit(x_train, y_train, epochs=5)
soft_model = tf.keras.Model(inputs, soft_o)
y_train_soft = soft_model.predict(x_train)
用soft target训练小模型,和上面基本一样:
conv_s = tf.keras.layers.Dense(64, activation=tf.nn.relu)(flat)
dr_s = tf.keras.layers.Dropout(0.2)(conv_s)
fin_s = tf.keras.layers.Dense(10)(dr_s)
outputs_s = tf.keras.layers.Softmax()(fin_s)
model_s = tf.keras.Model(inputs, outputs_s)
model_s.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model_s.fit(x_train, y_train_soft, epochs=5)
检验小模型,又需要重新用hard target,因此再建立一个Model:
model_e = tf.keras.Model(inputs, outputs_s)
model_e.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
loss, acc = model_e.evaluate(x_test, y_test)
print(loss)
print(acc)
准确率提升到96.8%,可以说是验证了Hinton的结论。
网友评论