深度學習 模型 剪枝

參考文章:

Pruning Filters for Efficient Convnets

Compressing deep neural nets

壓縮神經網絡 實驗記錄(剪枝 + rebirth + mobilenet)

爲了在手機上加速運行深度學習模型,目前實現的方式基本分爲兩類:一是深度學習框架層面的加速,另一個方向是深度學習模型層面的加速。

深度學習模型的加速又可以分爲採用新的卷積算子來加速模型,另一個方向是通過對已有模型進行剪枝操作得到一個參數更少的模型來加速模型。

通過觀察深度學習模型,可以發現其中很多kernel的權重很小,均在-1~1之間震盪,對於這些絕對值很小的參數,可以視其對整體模型貢獻很小,將其刪除,然後將剩餘的權重構成新的模型,以達到模型壓縮,加速,並保證精準度不變的目的。

基本步驟:

1.實現原始網絡,並將其訓練到收斂,保存權重

2.觀察對每一層的權重,判斷其對模型的貢獻大小,刪除貢獻較小的kernel,評判標準可以是std,sum(abs),mean等

3.當刪除部分kernel後,會導致輸出層的channel數變化,需要刪除輸出層對應kernel的對應channel

4.構建剪枝後的網絡,加載剪枝後的權重,與原模型對比精準度。

5.使用較小的學習率,rebirth剪枝後的模型

6.重複第1步

上圖展示了conv的kernel剪枝後導致的輸出維度變化

對於conv層後面接續全連接層的情況:

conv層在接續全連接層前,會先reshape爲一個維度。假設conv層輸出爲 (h,w,c),其會reshape爲 h*w*c, 假設刪除的kernel下標爲[ 2,5,7],對應的conv輸出通道也會減少 [2,5,7] 。reshape後 會減少 [2,5,7,...,h*w*2,h*w*5,h*w*7]。

全連接層接全連接層的邏輯基本和conv接conv層的邏輯一樣。

一個使用mnist的簡單示例

# 讀取保存的權重和所有訓練的var
model_path = './checkpoints/net_2018-12-19-10-05-17.ckpt-99900'
reader = tf.train.NewCheckpointReader(model_path)
all_variables = reader.get_variable_to_shape_map()
{'conv1/biases': [16],
 'conv1/weights': [3, 3, 1, 16],
 'conv2/biases': [32],
 'conv2/weights': [3, 3, 16, 32],
 'conv3/biases': [32],
 'conv3/weights': [3, 3, 32, 32],
 'fc1/biases': [128],
 'fc1/weights': [512, 128],
 'fc2/biases': [256],
 'fc2/weights': [128, 256],
 'global_step': [],
 'logits/biases': [10],
 'logits/weights': [256, 10]}
# 分析 conv1 的權重
conv1_weight = reader.get_tensor("conv1/weights")
# 計算每個kernel權重的和 (也可以使用其他指標,如std,mean等)
conv1_weight_sum = np.sum(conv1_weight, (0,1,2))
sort_conv1_weights = np.sort(conv1_weight_sum)
# 繪製conv1的
x = np.arange(0,len(sort_conv1_weights),step=1)
plt.plot(x,sort_conv1_weights)

# 保留權重和最大的8個kernel
pure_conv1_weight_index = np.where(conv1_weight_sum >= sort_conv1_weights[8])
pure_conv1_weight = conv1_weight[:,:,:,pure_conv1_weight_index[0]]
# conv1對應的bias 也做相同處理
conv1_bias = reader.get_tensor("conv1/biases")
pure_conv1_bias = conv1_bias[pure_conv1_weight_index[0]]
# 對後面接續的 conv 層的kernel做相同處理
conv2_weight = reader.get_tensor("conv2/weights")
conv2_bias = reader.get_tensor("conv2/biases")
conv2_weight = conv2_weight[:,:,pure_conv1_weight_index[0],:]

後面層重複以上操作

剪枝後結果對比

原始模型精度

剪枝後模型精度

模型權重大小從400多kb減小到了100多kb

jupyter文件及代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章