如何使用模型優化將Keras模型壓縮五倍


隨着我們對深度學習網絡認知的加深,在實際應用過程中,我們一定會厭倦深度網絡訓練時間長,參數規模太大而感到非常痛苦.那么今天我給大家帶來的是如何實現網絡剪枝.也就是在不降低准確度的情況下減少訓練參數的數量,加快訓練時間.從而大大節約我們得成本,這在實際應用中至關重要.

 

 

我們將演示如何使用TensorFlow模型優化將Keras模型的大小縮小5倍,這對於在資源受限的環境中進行部署特別重要。其次我們需要清楚剪枝剪去的是什么,剪枝剛開始的時候大家認為減去的是權重, 但是18年有好幾篇論文提出剪枝更像是一種模型結構搜索, 跟權重關系不大. 如rethinking the value of network pruning.剪枝是一種結構搜索, 減去的是一個filter,神經元. 剪完后的結構需要刪除對應的特征圖,還有權重,但本質上網絡結構的改變. 思路源頭都是來自於Oracle pruning 的方法,即挑選出模型中不重要的參數,將其剔除而不會對模型的效果造成太大的影響。在剔除不重要的參數之后,通過一個retrain的過程來恢復模型的性能。如何找到一個有效的對參數重要性的評價手段,在這個方法中就尤為重要,我們也可以看到,這種評價標准花樣百出,各有不同,也很難判定那種方法更好。目前,基於模型裁剪的方法是最為簡單有效的模型壓縮方式.

權重修剪意味着消除權重張量中不必要的值。將不必要的神經網絡參數的值設置為零,以消除我們估計的神經網絡各層之間不必要的連接。這是在訓練過程中完成的,這樣會讓神經網絡產生自適應變化。下面讓我們來介紹它的原理以及實戰操作!

我們的實戰步驟將分程一下幾部分:

 

  1. 像往常一樣訓練Keras模型以達到可接受的精度。

  2. 准備好修剪Keras圖層或模型。

  3. 創建修剪計划並增加多次迭代模型時間。

  4. 通過從模型中刪除剪枝包來導出修剪后的模型。

  5. 通過可選的量化操作將Keras模型轉換為TensorFlow Lite。

我們在之前的預訓練模型已經達到了理想的精度,想要在保持性能的同時減小網絡尺寸。修剪API接口可以幫助實現這一目標.在這里我們需要安裝tensorflow-model-optimizationtf-nightly軟件包

pip uninstall -yq tensorflowpip uninstall -yq tf-nightlypip install -Uq tf-nightly-gpupip install -q tensorflow-model-optimization

然后,我們可以加載先前訓練好的模型並將其轉換成“可修剪”模式。基於Keras的API可以直接使用單個層或整個模型。先前我們已經對整個模型進行了預訓練,因此呢,將修剪應用於整個模型將更加容易。該算法將應用於能夠進行權重修剪的所有網絡層。對於修剪計划,我們先將稀疏度設置為50%,然后逐步訓練模型達到稀疏度90%。X%稀疏度意味着X的權重張量將被修剪掉。

此外,我們給模型一些時間用於每個修剪步驟之后的恢復,因此修剪不會在每個步驟上都發生。我們將修剪的frequency為100。與修剪盆景類似,我們在修減的時候不能一次到位,我們不可能一天內砍掉90%的樹枝。

鑒於模型已經達到令人滿意的精度,我們可以立即開始修剪。我們在begin_step此處將其設置為0,並且只訓練另外四個時期。根據給定訓練示例的數量,批處理大小以及訓練的總時間,計算出訓練迭代次數。

 
        
import numpy as npimport tensorflow as tffrom 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 = 4end_step = np.ceil(1.0 * num_train_samples / batch_size).astype(np.int32) * epochsprint(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(), sparsity.PruningSummaries(log_dir=logdir, profile_batch=0)]
new_pruned_model.fit(x_train, y_train, 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)print('Test loss:', score[0])print('Test accuracy:', score[1])

修剪后的模型的測試損失和准確性應與原始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 tempfileimport 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 filetflite_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 = [tf.lite.Optimize.OPTIMIZE_FOR_SIZE]

 

與原始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也將將提供此類功能。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM