隨着我們對深度學習網絡認知的加深,在實際應用過程中,我們一定會厭倦深度網絡訓練時間長,參數規模太大而感到非常痛苦.那么今天我給大家帶來的是如何實現網絡剪枝.也就是在不降低准確度的情況下減少訓練參數的數量,加快訓練時間.從而大大節約我們得成本,這在實際應用中至關重要.
我們將演示如何使用TensorFlow模型優化將Keras模型的大小縮小5倍,這對於在資源受限的環境中進行部署特別重要。其次我們需要清楚剪枝剪去的是什么,剪枝剛開始的時候大家認為減去的是權重, 但是18年有好幾篇論文提出剪枝更像是一種模型結構搜索, 跟權重關系不大. 如rethinking the value of network pruning.剪枝是一種結構搜索, 減去的是一個filter,神經元. 剪完后的結構需要刪除對應的特征圖,還有權重,但本質上網絡結構的改變. 思路源頭都是來自於Oracle pruning 的方法,即挑選出模型中不重要的參數,將其剔除而不會對模型的效果造成太大的影響。在剔除不重要的參數之后,通過一個retrain的過程來恢復模型的性能。如何找到一個有效的對參數重要性的評價手段,在這個方法中就尤為重要,我們也可以看到,這種評價標准花樣百出,各有不同,也很難判定那種方法更好。目前,基於模型裁剪的方法是最為簡單有效的模型壓縮方式.
權重修剪意味着消除權重張量中不必要的值。將不必要的神經網絡參數的值設置為零,以消除我們估計的神經網絡各層之間不必要的連接。這是在訓練過程中完成的,這樣會讓神經網絡產生自適應變化。下面讓我們來介紹它的原理以及實戰操作!
我們的實戰步驟將分程一下幾部分:
-
像往常一樣訓練Keras模型以達到可接受的精度。
-
准備好修剪Keras圖層或模型。
-
創建修剪計划並增加多次迭代模型時間。
-
通過從模型中刪除剪枝包來導出修剪后的模型。
-
通過可選的量化操作將Keras模型轉換為TensorFlow Lite。
我們在之前的預訓練模型已經達到了理想的精度,想要在保持性能的同時減小網絡尺寸。修剪API接口可以幫助實現這一目標.在這里我們需要安裝tensorflow-model-optimization
和tf-nightly
軟件包
pip uninstall -yq tensorflow
pip uninstall -yq tf-nightly
pip install -Uq tf-nightly-gpu
pip install -q tensorflow-model-optimization
然后,我們可以加載先前訓練好的模型並將其轉換成“可修剪”模式。基於Keras的API可以直接使用單個層或整個模型。先前我們已經對整個模型進行了預訓練,因此呢,將修剪應用於整個模型將更加容易。該算法將應用於能夠進行權重修剪的所有網絡層。對於修剪計划,我們先將稀疏度設置為50%,然后逐步訓練模型達到稀疏度90%。X%稀疏度意味着X的權重張量將被修剪掉。
此外,我們給模型一些時間用於每個修剪步驟之后的恢復,因此修剪不會在每個步驟上都發生。我們將修剪的frequency
為100。與修剪盆景類似,我們在修減的時候不能一次到位,我們不可能一天內砍掉90%的樹枝。
鑒於模型已經達到令人滿意的精度,我們可以立即開始修剪。我們在begin_step
此處將其設置為0,並且只訓練另外四個時期。根據給定訓練示例的數量,批處理大小以及訓練的總時間,計算出訓練迭代次數。
import numpy as np
import tensorflow as tf
from tensorflow_model_optimization.sparsity import keras as sparsity
#Backend agnostic way to save/restore models
#_, keras_file = tempfile.mkstemp('.h5')
#print('Saving model to: ', keras_file)
#tf.keras.models.save_model(model, keras_file, include_optimizer=False)
#Load the serialized model
loaded_model = tf.keras.models.load_model(keras_file)
epochs = 4
end_step = np.ceil(1.0 * num_train_samples / batch_size).astype(np.int32) * epochs
print(end_step)
new_pruning_params = {
'pruning_schedule': sparsity.PolynomialDecay(initial_sparsity=0.50,
final_sparsity=0.90,
begin_step=0,end_step=end_step,
frequency=100)
}
new_pruned_model = sparsity.prune_low_magnitude(loaded_model, new_pruning_params)
new_pruned_model.summary()
new_pruned_model.compile(
loss=tf.keras.losses.categorical_crossentropy,
optimizer='adam',
metrics=['accuracy'])
現在我們開始訓練和修剪模型。
#Add a pruning step callback to peg the pruning step to the optimizer's
#step. Also add a callback to add pruning summaries to tensorboard
callbacks = [
sparsity.UpdatePruningStep(),
batch_size=batch_size,
epochs=epochs,
verbose=1,
callbacks=callbacks,
validation_data=(x_test, y_test))
score = new_pruned_model.evaluate(x_test, y_test, verbose=0)
修剪后的模型的測試損失和准確性應與原始Keras模型相似。
這些修剪包可以像下面這樣輕松地刪除,之后參數的總數應與原始模型相同。
final_model = sparsity.strip_pruning(pruned_model)
final_model.summary()
現在,可以通過將權重與零進行比較來檢查權重刪減的百分比。
下圖是修剪了90%的卷積,密集度和批處理規范層的權重。
from tensorflow.keras.models import load_model
model = load_model(final_model)
import numpy as np
for i, w in enumerate(model.get_weights()):
print(
"{} -- Total:{}, Zeros: {:.2f}%".format(
model.weights[i].name, w.size, np.sum(w == 0) / w.size * 100
)
)
現在,僅使用通用文件壓縮算法(例如zip),Keras模型將減少5倍。
壓縮前修剪的模型的大小:12.52 Mb 壓縮后修剪的模型的大小:2.51 Mb
import tempfile
import zipfile
_, new_pruned_keras_file = tempfile.mkstemp(".h5")
print("Saving pruned model to: ", new_pruned_keras_file)
tf.keras.models.save_model(final_model, new_pruned_keras_file, include_optimizer=False)
#Zip the .h5 model file
_, zip3 = tempfile.mkstemp(".zip")
with zipfile.ZipFile(zip3, "w", compression=zipfile.ZIP_DEFLATED) as f:
f.write(new_pruned_keras_file)
print(
"Size of the pruned model before compression: %.2f Mb"
% (os.path.getsize(new_pruned_keras_file) / float(2 ** 20))
)
print(
"Size of the pruned model after compression: %.2f Mb"
% (os.path.getsize(zip3) / float(2 ** 20))
Tensorflow Lite是可用於部署到移動設備的示例格式。要轉換為Tensorflow Lite圖,必須使用TFLiteConverter
以下代碼:
#Create the .tflite file
tflite_model_file = "/tmp/sparse_mnist.tflite" converter = tf.lite.TFLiteConverter.from_keras_model_file(pruned_keras_file) tflite_model = converter.convert() with open(tflite_model_file, "wb") as f: f.write(tflite_model)
然后,我們可以使用類似的技術來壓縮tflite
文件,並將文件大小減小5倍。訓練后量化使權重轉換為8位精度,這是從keras模型到TFLite的平面緩沖區的模型轉換的一部分,從而使模型大小又減小了4倍。只需在調用之前將以下行添加到上一個代碼段即可:
converter.optimizations =
與原始Keras模型的12.52 Mb相比,壓縮的8位tensorflow lite模型僅耗費0.60 Mb,同時保持了相當的測試精度。尺寸總共減少了16倍。
我們可以像這樣評估轉換后的TensorFlow Lite模型的准確性,並在eval_model
其中向測試數據集輸入。
import numpy as np
interpreter = tf.lite.Interpreter(model_path=str(tflite_model_file))
interpreter.allocate_tensors()
input_index = interpreter.get_input_details()[0]["index"]
output_index = interpreter.get_output_details()[0]["index"]
def eval_model(interpreter, x_test, y_test):
total_seen = 0
num_correct = 0
for img, label in zip(x_test, y_test):
inp = img.reshape((1, 28, 28, 1))
total_seen += 1
interpreter.set_tensor(input_index, inp)
interpreter.invoke()
predictions = interpreter.get_tensor(output_index)
if np.argmax(predictions) == np.argmax(label):
num_correct += 1
if total_seen % 1000 == 0:
print("Accuracy after %i images: %f" %
(total_seen, float(num_correct) / float(total_seen)))
return float(num_correct) / float(total_seen)
print(eval_model(interpreter, x_test, y_test))
在本教程中,我們展示了如何使用TensorFlow模型優化工具包,權重修剪API 創建稀疏模型。現在可以創建占用磁盤空間少得多的模型。生成的模型也可以更有效地實現以避免復雜計算;將來,TensorFlow Lite也將將提供此類功能。