# 8.1 命令式和符號式混合編程
本書到目前為止一直都在使用命令式編程,它使用編程語句改變程序狀態。考慮下面這段簡單的命令式程序。
``` python
def add(a, b):
return a + b
def fancy_func(a, b, c, d):
e = add(a, b)
f = add(c, d)
g = add(e, f)
return g
fancy_func(1, 2, 3, 4) # 10
```
和我們預期的一樣,在運行語句`e = add(a, b)`時,Python會做加法運算并將結果存儲在變量`e`中,從而令程序的狀態發生改變。類似地,后面的兩條語句`f = add(c, d)`和`g = add(e, f)`會依次做加法運算并存儲變量。
雖然使用命令式編程很方便,但它的運行可能很慢。一方面,即使`fancy_func`函數中的`add`是被重復調用的函數,Python也會逐一執行這3條函數調用語句。另一方面,我們需要保存變量`e`和`f`的值直到`fancy_func`中所有語句執行結束。這是因為在執行`e = add(a, b)`和`f = add(c, d)`這2條語句之后我們并不知道變量`e`和`f`是否會被程序的其他部分使用。
與命令式編程不同,符號式編程通常在計算流程完全定義好后才被執行。多個深度學習框架,如**Theano和TensorFlow,都使用了符號式編程**。通常,符號式編程的程序需要下面3個步驟:
1. 定義計算流程;
2. 把計算流程編譯成可執行的程序;
3. 給定輸入,調用編譯好的程序執行。
下面我們用符號式編程重新實現本節開頭給出的命令式編程代碼。
``` python
def add_str():
return '''
def add(a, b):
return a + b
'''
def fancy_func_str():
return '''
def fancy_func(a, b, c, d):
e = add(a, b)
f = add(c, d)
g = add(e, f)
return g
'''
def evoke_str():
return add_str() + fancy_func_str() + '''
print(fancy_func(1, 2, 3, 4))
'''
prog = evoke_str()
print(prog)
y = compile(prog, '', 'exec')
exec(y)
```
輸出:
```
def add(a, b):
return a + b
def fancy_func(a, b, c, d):
e = add(a, b)
f = add(c, d)
g = add(e, f)
return g
print(fancy_func(1, 2, 3, 4))
10
```
以上定義的3個函數都僅以字符串的形式返回計算流程。最后,我們通過`compile`函數編譯完整的計算流程并運行。由于在編譯時系統能夠完整地獲取整個程序,因此有更多空間優化計算。例如,編譯的時候可以將程序改寫成`print((1 + 2) + (3 + 4))`,甚至直接改寫成`print(10)`。這樣不僅減少了函數調用,還節省了內存。
對比這兩種編程方式,我們可以看到以下兩點。
* 命令式編程更方便。當我們在Python里使用命令式編程時,大部分代碼編寫起來都很直觀。同時,命令式編程更容易調試。這是因為我們可以很方便地獲取并打印所有的中間變量值,或者使用Python的調試工具。
* 符號式編程更高效并更容易移植。一方面,在編譯的時候系統容易做更多優化;另一方面,符號式編程可以將程序變成一個與Python無關的格式,從而可以使程序在非Python環境下運行,以避開Python解釋器的性能問題。
## 8.1.1 混合式編程取兩者之長
大部分深度學習框架在命令式編程和符號式編程之間二選一。例如,**Theano和受其啟發的后來者TensorFlow使用了符號式編程,Chainer和它的追隨者PyTorch使用了命令式編程,而Gluon則采用了混合式編程的方式**。
......
> 由于PyTorch僅僅采用了命令式編程,所以跳過本節剩余部分,感興趣的可以去看[原文](https://zh.d2l.ai/chapter_computational-performance/hybridize.html)
- Home
- Introduce
- 1.深度學習簡介
- 深度學習簡介
- 2.預備知識
- 2.1環境配置
- 2.2數據操作
- 2.3自動求梯度
- 3.深度學習基礎
- 3.1 線性回歸
- 3.2 線性回歸的從零開始實現
- 3.3 線性回歸的簡潔實現
- 3.4 softmax回歸
- 3.5 圖像分類數據集(Fashion-MINST)
- 3.6 softmax回歸的從零開始實現
- 3.7 softmax回歸的簡潔實現
- 3.8 多層感知機
- 3.9 多層感知機的從零開始實現
- 3.10 多層感知機的簡潔實現
- 3.11 模型選擇、反向傳播和計算圖
- 3.12 權重衰減
- 3.13 丟棄法
- 3.14 正向傳播、反向傳播和計算圖
- 3.15 數值穩定性和模型初始化
- 3.16 實戰kaggle比賽:房價預測
- 4 深度學習計算
- 4.1 模型構造
- 4.2 模型參數的訪問、初始化和共享
- 4.3 模型參數的延后初始化
- 4.4 自定義層
- 4.5 讀取和存儲
- 4.6 GPU計算
- 5 卷積神經網絡
- 5.1 二維卷積層
- 5.2 填充和步幅
- 5.3 多輸入通道和多輸出通道
- 5.4 池化層
- 5.5 卷積神經網絡(LeNet)
- 5.6 深度卷積神經網絡(AlexNet)
- 5.7 使用重復元素的網絡(VGG)
- 5.8 網絡中的網絡(NiN)
- 5.9 含并行連結的網絡(GoogLeNet)
- 5.10 批量歸一化
- 5.11 殘差網絡(ResNet)
- 5.12 稠密連接網絡(DenseNet)
- 6 循環神經網絡
- 6.1 語言模型
- 6.2 循環神經網絡
- 6.3 語言模型數據集(周杰倫專輯歌詞)
- 6.4 循環神經網絡的從零開始實現
- 6.5 循環神經網絡的簡單實現
- 6.6 通過時間反向傳播
- 6.7 門控循環單元(GRU)
- 6.8 長短期記憶(LSTM)
- 6.9 深度循環神經網絡
- 6.10 雙向循環神經網絡
- 7 優化算法
- 7.1 優化與深度學習
- 7.2 梯度下降和隨機梯度下降
- 7.3 小批量隨機梯度下降
- 7.4 動量法
- 7.5 AdaGrad算法
- 7.6 RMSProp算法
- 7.7 AdaDelta
- 7.8 Adam算法
- 8 計算性能
- 8.1 命令式和符號式混合編程
- 8.2 異步計算
- 8.3 自動并行計算
- 8.4 多GPU計算
- 9 計算機視覺
- 9.1 圖像增廣
- 9.2 微調
- 9.3 目標檢測和邊界框
- 9.4 錨框
- 10 自然語言處理
- 10.1 詞嵌入(word2vec)
- 10.2 近似訓練
- 10.3 word2vec實現
- 10.4 子詞嵌入(fastText)
- 10.5 全局向量的詞嵌入(Glove)
- 10.6 求近義詞和類比詞
- 10.7 文本情感分類:使用循環神經網絡
- 10.8 文本情感分類:使用卷積網絡
- 10.9 編碼器--解碼器(seq2seq)
- 10.10 束搜索
- 10.11 注意力機制
- 10.12 機器翻譯