無論是在機器學習還是深度學習中,Python 已經成為主導性的編程語言。而且,現在許多主流的深度學習框架,例如 PyTorch、TensorFlow 也都是基於 Python。這門課主要是圍繞 “理論 + 實戰” 同時進行的,所以本文,我將重點介紹深度學習中 Python 的必備知識點。
為什麼選擇 Python
Python 是一種面向對象的解釋型計算機程序設計語言,由荷蘭人 Guido van Rossum 於 1989 年發明,第一個公開發行版發行於 1991 年。Python 具有豐富和強大的庫。它常被暱稱為膠水語言,能夠把用其他語言製作的各種模塊(尤其是 C/C++)很輕鬆地聯結在一起。
為什麼人工智能、深度學習會選擇 Python 呢?一方面是因為 Python 作為一門解釋型語言,入門簡單、容易上手。另一方面是因為 Python 的開發效率高,Python 有很多庫很方便做人工智能,比如 Numpy、Scipy 做數值計算的,Sklearn 做機器學習的,Matplotlib 將數據可視化的,等等。總的來說,Python 既容易上手,又是功能強大的編程語言。按照《Python 學習手冊》作者的說法,Python 可以從支持航空航天器系統的開發到小遊戲開發的幾乎所有的領域。
其實,人工智能的核心算法的底層還是由 C/C++ 編寫的,因為是計算密集型,需要非常精細的優化,還需要 GPU、專用硬件之類的接口,這些都只有 C/C++ 能做到。Python 實際上是實現 API 調用的功能,例如所有的深度學習框架 PyTorch、TensorFlow 等,底層都是由 C/C++ 編寫的。由於 Python 是頂層高級語言,它的缺點就是運行速度慢,但是這絲毫不影響 Python 的普及。如今,在 GPU 加速的前提下,Python 的運行速度已經很快了。在眾多因素影響下,Python 毫無疑問成為了人工智能的最主要的編程語言。
下面這張圖來自 TIOBE 編程社區 Top 10 編程語言 TIOBE 指數走勢(2002-2018):
如今,Python 排名已經僅次於 Java、C、C++ 之後,排名第四,且呈逐年上升的趨勢。而在人工智能領域,Python 是當之無愧的第一。
Python 目前有兩個版本:2 和 3。人工智能領域主要使用 Python 3,建議安裝 Python 3 版本。你也可以使用如下命令來查看當前安裝的是哪個版本:
python --version
函數 Function 與類 Class
Python 中的函數以關鍵字 def 來定義,例如:
def sign(x):
if x > 0:
return 'positive'
elif x < 0:
return 'negative'
else:
return 'zero'
for x in [-1, 0, 1]:
print(sign(x))
# Prints "negative", "zero", "positive"
上面呢,就是定義一個 sign 函數,根據輸入 x 與 0 的大小關係,返回 positive、negative 或 zero。
函數的形參也可以設置成默認值,例如:
def greet(name, loud=False):
if loud:
print('HELLO, %s!' % name.upper())
else:
print('Hello, %s' % name)
greet('Will') # Prints "Hello, Will"
greet('Tony', loud=True) # Prints "HELLO, TONY!"
Python 中的類的概念和其他語言相比沒什麼不同,例如:
class Greeter(object):
# Constructor
def __init__(self, name):
self.name = name # Create an instance variable
# Instance method
def greet(self, loud=False):
if loud:
print('HELLO, %s!' % self.name.upper())
else:
print('Hello, %s' % self.name)
g = Greeter('Will') # Construct an instance of the Greeter class
g.greet() # Call an instance method; prints "Hello, Will"
g.greet(loud=True) # Call an instance method; prints "HELLO, WILL!"
__init__ 函數是類的初始化函數,所有成員變量都是 self 的,所以初始化函數一般都包含 self 參數。name 是類中函數將要調用的輸入參數。
Python 中類的繼承也非常簡單,最基本的繼承方式就是定義類的時候把父類往括號裡一放就行了:
class Know(Greeter):
"""Class Know inheritenced from Greeter"""
def meet(self):
print('Nice to meet you!')
k = Know('Will') # Construct an instance of the Greater class
k.greet() # Call an instance method; prints "Hello, Will"
k.meet() # Call an instance method; prints "Nice to meet you!"
向量化和矩陣
深度學習神經網絡模型包含了大量的矩陣相乘運算,如果使用 for 循環,運算速度會大大降低。Python 中可以使用 dot 函數進行向量化矩陣運算,來提高網絡運算效率。我們用一個例子來比較說明 for 循環和矩陣運算各自的時間差異性。
import numpy as np
import time
a = np.random.rand(100000)
b = np.random.rand(100000)
tic = time.time()
for i in range(100000):
c += a[i]*b[i]
toc = time.time()
print(c)
print("for loop:" + str(1000*(toc-tic)) + "ms")
c = 0
tic = time.time()
c = np.dot(a,b)
toc = time.time()
print(c)
print("Vectorized:" + str(1000*(toc-tic)) + "ms")
輸出結果為:
>> 274877.869751
>> for loop:99.99990463256836ms
>> 24986.1673877
>> Vectorized:0.9999275207519531ms
顯然,兩個矩陣相乘,使用 for 循環需要大約 100 ms,而使用向量化矩陣運算僅僅需要大約 1 ms,效率得到了極大的提升。值得一提的是,神經網絡模型有的矩陣維度非常大,這時候,使用矩陣直接相乘會更大程度地提高速度。所以,在構建神經網絡模型時,我們應該儘量使用矩陣相乘運算,減少 for 循環的使用。
順便提一下,為了加快深度學習神經網絡運算速度,可以使用比 CPU 運算能力更強大的 GPU。事實上,GPU 和 CPU 都有並行指令(Parallelization Instructions),稱為 Single Instruction Multiple Data(SIMD)。SIMD 是單指令多數據流,能夠複製多個操作數,並把它們打包在大型寄存器的一組指令集。SIMD 能夠大大提高程序運行速度,並行運算也就是向量化矩陣運算更快的原因。相比而言,GPU 的 SIMD 要比 CPU 更強大。
廣播 Broadcasting
Python 中的廣播(Broadcasting)機制非常強大,在神經網絡模型矩陣運算中非常有用。廣播機制主要包括以下幾個部分:
- 讓所有輸入數組都向其中 shape 最長的數組看齊,shape 中不足的部分都通過在前面加1補齊。
- 輸出數組的 shape 是輸入數組 shape 的各個軸上的最大值。
- 如果輸入數組的某個軸和輸出數組的對應軸的長度相同或者其長度為 1 時,這個數組能夠用來計算,否則出錯。
- 當輸入數組的某個軸的長度為 1 時,沿著此軸運算時都用此軸上的第一組值。
如果覺得上面幾條機制比較晦澀難懂,沒關係。簡而言之,就是 Python 中可以對不同維度的矩陣進行四則混合運算,但至少保證有一個維度是相同的。下面我舉幾個簡單的例子,你就明白了。
是不是覺得廣播機制很方便?這也正是 Python 強大的地方,能夠幫我們省很多事。
值得一提的是,在 Python 程序中為了保證矩陣運算正確,可以使用 reshape 函數設定矩陣為所需的維度。這是一個很好且有用的習慣。例如:
x.reshape(2,3)
關於矩陣維度,還有一些需要注意的地方。例如,我們定義一個向量,可能會這樣寫:
a = np.random.randn(6)
上面這條語句生成的向量維度既不是(6,1),也不是(1,6),而是(6,)。它既不是列向量也不是行向量,而是 rank 1 array。rank 1 array 的特點是它的轉置還是它本身。這種定義實際應用中可能會帶來一些問題,如果我們想要定義行向量或者列向量的話,最好這樣寫:
a = np.random.randn(1,6)
a = np.random.randn(6,1)
另外,我們還可以使用 assert 語句對向量或者數組維度進行判斷。如果與給定的維度不同,則程序在此處停止運行。assert 的靈活使用可以幫助我們及時檢查神經網絡模型中參數的維度是否正確。
assert(a == shape(6,1))
Matplotlib 繪圖
Matplotlib 是 Python 一個強大的繪圖庫,下面我將簡單介紹一下 matplotlib.pyplot 模塊。
plot 是 Matplotlib 主要的 2D 繪圖函數,舉個簡單的例子:
import numpy as np
import matplotlib.pyplot as plt
# Compute the x and y coordinates
x = np.arange(0, 4 * np.pi, 0.1)
y = np.sin(x)
# Plot the points using matplotlib
plt.plot(x, y)
plt.show() # You must call plt.show() to make graphics appear.
我們也可以在一張圖片中同時畫多個曲線:
import numpy as np
import matplotlib.pyplot as plt
# Compute the x and y coordinates
x = np.arange(0, 4 * np.pi, 0.1)
y_sin = np.sin(x)
y_cos = np.cos(x)
# Plot the points using matplotlib
plt.plot(x, y_sin)
plt.plot(x, y_cos)
plt.xlabel('x axis label')
plt.ylabel('y axis label')
plt.title('Sine and Cosine')
plt.legend(['Sine', 'Cosine'])
plt.show()
最後介紹一下圖片如何顯示:
import numpy as np
from scipy.misc import imread, imresize
import matplotlib.pyplot as plt
img = imread('./dog.jpg')
img_tinted = img * [0.9, 0.9, 0.8]
# Show the original image
plt.subplot(2, 1, 1)
plt.imshow(img)
# Show the tinted image
plt.subplot(2, 1, 2)
# we explicitly cast the image to uint8 before displaying it.
plt.imshow(np.uint8(img_tinted))
plt.show()
總結
本文主要介紹了一些 Python 的基礎知識,包括為什麼選擇 Python、函數和類、向量化和矩陣、廣播、Matplotlib 繪圖等。Python 的功能非常強大,其包含的內容也太多了,我們不可能在一篇文章裡介紹所有的 Python 知識。我在本文介紹的幾點內容是神經網絡編程的必備知識點,這些內容都會在接下來的章節編程中用到。
閱讀更多 Farmer001 的文章