文章目錄
概述
Numpy(Numerical Python的簡稱)是高性能科學計算和數據分析的基礎包。使用飛槳構建神經網絡模型時,通常會使用Numpy實現數據預處理和一些模型指標的計算,飛槳中的Tensor數據可以很方便的和ndarray數組進行相互轉換。
本節主要介紹Numpy如下功能:
- ndarray數組:一個具有矢量算術運算和複雜廣播能力的快速且節省空間的多維數組。
- 對整組數據進行快速運算的標準數學函數(無需編寫循環)。
- 線性代數、隨機數生成以及傅里葉變換功能。
- 讀寫磁盤數據、操作內存映射文件。
本質上,Numpy期望用戶在執行“向量”操作時,會像使用“標量”一樣輕鬆。大家可以先在本機上敲如下代碼,感受一下Numpy的便捷。
>>> import numpy as np
>>> a = np.array([1,2,3,4])
>>> b = np.array([10,20,30,40])
>>> c = a + b
>>> print (c)
[11 22 33 44]
基礎數據類型:ndarray數組
ndarray數組是Numpy的基礎數據結構式,可以靈活、高效的處理多個元素的操作。本節主要從如下五部分展開介紹:
- 爲什麼引入ndarray數組
- 如何創建ndarray數組
- ndarray數組的基本運算
- ndarray數組的切片和索引
- ndarray數組的統計運算
爲什麼引入ndarray數組
Python中的list列表也可以非常靈活的處理多個元素的操作,但效率卻非常低。與之比較,ndarray數組具有如下特點:
- ndarray數組中所有元素的數據類型相同、數據地址連續,批量操作數組元素時速度更快。而list列表中元素的數據類型可能不同,需要通過尋址方式找到下一個元素。
- ndarray數組支持廣播機制,矩陣運算時不需要寫for循環。
- Numpy底層使用c語言編寫,內置並行計算功能,運行速度高於Python代碼。
下面通過幾個實際例子體會一下,在完成同一個任務時,使用ndarray數組和list列表的差異。
案例1:實現a+1的計算
# Python原生的list
# 假設有兩個list
a = [1, 2, 3, 4, 5]
b = [2, 3, 4, 5, 6]
# 完成如下計算
# 對a的每個元素 + 1
# a = a + 1 不能這麼寫,會報錯
# a[:] = a[:] + 1 也不能這麼寫,也會報錯
for i in range(5):
a[i] = a[i] + 1
a
[2, 3, 4, 5, 6]
# 使用ndarray
import numpy as np
a = np.array([1, 2, 3, 4, 5])
a = a + 1
a
array([2, 3, 4, 5, 6])
案例2:實現c=a+b的計算
# 計算 a和b中對應位置元素的和,是否可以這麼寫?
a = [1, 2, 3, 4, 5]
b = [2, 3, 4, 5, 6]
c = a + b
# 檢查輸出發現,不是想要的結果
c
[1, 2, 3, 4, 5, 2, 3, 4, 5, 6]
# 使用for循環,完成兩個list對應位置元素相加
c = []
for i in range(5):
c.append(a[i] + b[i])
c
[3, 5, 7, 9, 11]
# 使用numpy中的ndarray完成兩個ndarray相加
import numpy as np
a = np.array([1, 2, 3, 4, 5])
b = np.array([2, 3, 4, 5, 6])
c = a + b
c
array([ 3, 5, 7, 9, 11])
通過上面的兩個案例可以看出,在不寫for循環的情況下,ndarray數組就可以非常方便的完成數學計算。在編寫矢量或者矩陣的程序時,可以像編寫普通數值一樣,使得代碼極其簡潔。
另外,ndarray數組還提供了廣播機制,它會按一定規則自動對數組的維度進行擴展以完成計算。如下面例子所示,1維數組和2維數組進行相加操作,ndarray數組會自動擴展1維數組的維度,然後再對每個位置的元素分別相加。
# 自動廣播機制,1維數組和2維數組相加
# 二維數組維度 2x5
# array([[ 1, 2, 3, 4, 5],
# [ 6, 7, 8, 9, 10]])
d = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])
# c是一維數組,維度5
# array([ 4, 6, 8, 10, 12])
c = np.array([ 4, 6, 8, 10, 12])
e = d + c
e
array([[ 5, 8, 11, 14, 17],
[10, 13, 16, 19, 22]])
創建ndarray數組
創建ndarray數組最簡單的方式就是使用array
函數,它接受一切序列型的對象(包括其他數組),然後產生一個新的含有傳入數據的numpy數組。下面通過實例體會下array
、arange
、zeros
、ones
四個主要函數的用法。
array
:創建將嵌套序列(比如由一組等長列表組成的列表),並轉換爲一個多維數組。
# 導入numpy
import numpy as np
# 從list創建array
a = [1,2,3,4,5,6] # 創建簡單的列表
b = np.array(a) # 將列表轉換爲數組
b
array([1, 2, 3, 4, 5, 6])
arange
:創建元素從0到10依次遞增2的數組。
# 通過np.arange創建
# 通過指定start, stop (不包括stop),interval來產生一個1維的ndarray
a = np.arange(0, 20, 2)
a
array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18])
zeros
:創建指定長度或者形狀的全0數組。
# 創建全0的ndarray
a = np.zeros([3,3])
a
array([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])
ones
:創建指定長度或者形狀的全1數組。
# 創建全1的ndarray
a = np.ones([3,3])
a
array([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]])
查看ndarray數組的屬性
ndarray的屬性包括shape
、dtype
、size
和ndim
等,通過如下代碼可以查看darray數組的屬性。
shape
:數組的形狀 ndarray.shape,1維數組(N, ),二維數組(M, N),三維數組(M, N, K)。dtype
:數組的數據類型。size
:數組中包含的元素個數 ndarray.size,其大小等於各個維度的長度的乘積。ndim
:數組的維度大小,ndarray.ndim, 其大小等於ndarray.shape所包含元素的個數。
a = np.ones([3, 3])
print('a, dtype: {}, shape: {}, size: {}, ndim: {}'.format(a.dtype, a.shape, a.size, a.ndim))
a, dtype: float64, shape: (3, 3), size: 9, ndim: 2
import numpy as np
b = np.random.rand(10, 10)
, 10)
b.shape
(10, 10)
b.size
100
b.ndim
2
b.dtype
dtype('float64')
改變ndarray數組的數據類型和形狀
創建ndarray之後,可以對其數據類型或形狀進行修改,代碼如下所示。
# 轉化數據類型
b = a.astype(np.int64)
print('b, dtype: {}, shape: {}'.format(b.dtype, b.shape))
# 改變形狀
c = a.reshape([1, 9])
print('c, dtype: {}, shape: {}'.format(c.dtype, c.shape))
b, dtype: int64, shape: (3, 3)
c, dtype: float64, shape: (1, 9)
ndarray數組的基本運算
ndarray數組可以像普通的數值型變量一樣進行加減乘除操作,主要包含如下兩種運算:
- 標量和ndarray數組之間的運算
- 兩個ndarray數組之間的運算
標量和ndarray數組之間的運算
標量和ndarray數組之間的運算主要包括除法、乘法、加法和減法運算,具體代碼如下所示。
# 標量除以數組,用標量除以數組的每一個元素
arr = np.array([[1., 2., 3.], [4., 5., 6.]])
1. / arr
array([[1. , 0.5 , 0.33333333],
[0.25 , 0.2 , 0.16666667]])
# 標量乘以數組,用標量乘以數組的每一個元素
arr = np.array([[1., 2., 3.], [4., 5., 6.]])
2.0 * arr
array([[ 2., 4., 6.],
[ 8., 10., 12.]])
# 標量加上數組,用標量加上數組的每一個元素
arr = np.array([[1., 2., 3.], [4., 5., 6.]])
2.0 + arr
array([[3., 4., 5.],
[6., 7., 8.]])
# 標量減去數組,用標量減去數組的每一個元素
arr = np.array([[1., 2., 3.], [4., 5., 6.]])
2.0 - arr
array([[ 1., 0., -1.],
[-2., -3., -4.]])
兩個ndarray數組之間的運算
兩個ndarray數組之間的運算主要包括減法、加法、乘法、除法和開根號運算,具體代碼如下所示。
# 數組 減去 數組, 用對應位置的元素相減
arr1 = np.array([[1., 2., 3.], [4., 5., 6.]])
arr2 = np.array([[11., 12., 13.], [21., 22., 23.]])
arr1 - arr2
array([[-10., -10., -10.],
[-17., -17., -17.]])
# 數組 加上 數組, 用對應位置的元素相加
arr1 = np.array([[1., 2., 3.], [4., 5., 6.]])
arr2 = np.array([[11., 12., 13.], [21., 22., 23.]])
arr1 + arr2
array([[12., 14., 16.],
[25., 27., 29.]])
# 數組 乘以 數組,用對應位置的元素相乘
arr1 * arr2
array([[ 11., 24., 39.],
[ 84., 110., 138.]])
# 數組 除以 數組,用對應位置的元素相除
arr1 / arr2
array([[0.09090909, 0.16666667, 0.23076923],
[0.19047619, 0.22727273, 0.26086957]])
# 數組開根號,將每個位置的元素都開根號
arr ** 0.5
array([[1. , 1.41421356, 1.73205081],
[2. , 2.23606798, 2.44948974]])
ndarray數組的索引和切片
在編寫模型過程中,通常需要訪問或者修改ndarray數組某個位置的元素,則需要使用ndarray數組的索引。有些情況下可能需要訪問或者修改一些區域的元素,則需要使用ndarray數組的切片。
ndarray數組的索引和切片的使用方式與Python中的list類似。通過[ -n , n-1 ]的下標進行索引,通過內置的slice
函數,設置其start
,stop
和step
參數進行切片,從原數組中切割出一個新數組。
ndarray數組的索引是一個內容豐富的主題,因爲選取數據子集或的單個元素的方式有很多。下面從一維數組和多維數組兩個維度介紹索引和切片的方法。
一維ndarray數組的索引和切片
從表面上看,一維數組跟Python列表的功能類似,它們重要區別在於:數組切片產生的新數組,還是指向原來的內存區域,數據不會被複制,視圖上的任何修改都會直接反映到源數組上。將一個標量值賦值給一個切片時,該值會自動傳播到整個選區。
# 1維數組索引和切片
a = np.arange(30)
a[10]
10
a = np.arange(30)
b = a[4:7]
b
array([4, 5, 6])
#將一個標量值賦值給一個切片時,該值會自動傳播到整個選區。
a = np.arange(30)
a[4:7] = 10
a
array([ 0, 1, 2, 3, 10, 10, 10, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29])
# 數組切片產生的新數組,還是指向原來的內存區域,數據不會被複制。
# 視圖上的任何修改都會直接反映到源數組上。
a = np.arange(30)
arr_slice = a[4:7]
arr_slice[0] = 100
a, arr_slice
(array([ 0, 1, 2, 3, 100, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29]), array([100, 5, 6]))
# 通過copy給新數組創建不同的內存空間
a = np.arange(30)
arr_slice = a[4:7]
arr_slice = np.copy(arr_slice)
arr_slice[0] = 100
a, arr_slice
(array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]),
array([100, 5, 6]))
多維ndarray數組的索引和切片
多維ndarray數組的索引和切片具有如下特點:
- 在多維數組中,各索引位置上的元素不再是標量而是多維數組。
- 以逗號隔開的索引列表來選取單個元素。
- 在多維數組中,如果省略了後面的索引,則返回對象會是一個維度低一點的ndarray。
多維ndarray數組的索引和切片代碼如下所示。
# 多維數組索引和切片
a = np.arange(30)
arr3d = a.reshape(5, 3, 2)
arr3d
array([[[ 0, 1],
[ 2, 3],
[ 4, 5]],
[[ 6, 7],
[ 8, 9],
[10, 11]],
[[12, 13],
[14, 15],
[16, 17]],
[[18, 19],
[20, 21],
[22, 23]],
[[24, 25],
[26, 27],
[28, 29]]])
# 只有一個索引指標時,會在第0維上索引,後面的維度保持不變
arr3d[0]
array([[0, 1],
[2, 3],
[4, 5]])
# 兩個索引指標
arr3d[0][1]
array([2, 3])
# 兩個索引指標
arr3d[0, 1]
array([2, 3])
# 使用python中的for語法對數組切片
a = np.arange(24)
a
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23])
a = a.reshape([6, 4])
a
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]])
# 使用for語句生成list
[k for k in range(0, 6, 2)]
[0, 2, 4]
# 結合上面列出的for語句的用法
# 使用for語句對數組進行切片
# 下面的代碼會生成多個切片構成的list
# k in range(0, 6, 2) 決定了k的取值可以是0, 2, 4
# 產生的list的包含三個切片
# 第一個元素是a[0 : 0+2],
# 第二個元素是a[2 : 2+2],
# 第三個元素是a[4 : 4+2]
slices = [a[k:k+2] for k in range(0, 6, 2)]
slices
[array([[0, 1, 2, 3],
[4, 5, 6, 7]]), array([[ 8, 9, 10, 11],
[12, 13, 14, 15]]), array([[16, 17, 18, 19],
[20, 21, 22, 23]])]
slices[0]
array([[0, 1, 2, 3],
[4, 5, 6, 7]])
ndarray數組的統計方法
可以通過數組上的一組數學函數對整個數組或某個軸向的數據進行統計計算。主要包括如下統計方法:
mean
:計算算術平均數,零長度數組的mean爲NaN。std
和var
:計算標準差和方差,自由度可調(默認爲n)。sum
:對數組中全部或某軸向的元素求和,零長度數組的sum爲0。max
和min
:計算最大值和最小值。argmin
和argmax
:分別爲最大和最小元素的索引。cumsum
:計算所有元素的累加。cumprod
:計算所有元素的累積。
說明:
sum、mean以及標準差std等聚合計算既可以當做數組的實例方法調用,也可以當做Numpy函數使用。
# 計算均值,使用arr.mean() 或 np.mean(arr),二者是等價的
arr = np.array([[1,2,3], [4,5,6], [7,8,9]])
arr.mean(), np.mean(arr)
(5.0, 5.0)
# 求和
arr.sum(), np.sum(arr)
(45, 45)
# 求最大值
arr.max(), np.max(arr)
(9, 9)
# 求最小值
arr.min(), np.min(arr)
(1, 1)
# 指定計算的維度
# 沿着第1維求平均,也就是將[1, 2, 3]取平均等於2,[4, 5, 6]取平均等於5,[7, 8, 9]取平均等於8
arr.mean(axis = 1)
array([2., 5., 8.])
# 沿着第0維求和,也就是將[1, 4, 7]求和等於12,[2, 5, 8]求和等於15,[3, 6, 9]求和等於18
arr.sum(axis=0)
array([12, 15, 18])
# 沿着第0維求最大值,也就是將[1, 4, 7]求最大值等於7,[2, 5, 8]求最大值等於8,[3, 6, 9]求最大值等於9
arr.max(axis=0)
array([7, 8, 9])
# 沿着第1維求最小值,也就是將[1, 2, 3]求最小值等於1,[4, 5, 6]求最小值等於4,[7, 8, 9]求最小值等於7
arr.min(axis=1)
array([1, 4, 7])
# 計算標準差
arr.std()
2.581988897471611
# 計算方差
arr.var()
6.666666666666667
# 找出最大元素的索引
arr.argmax(), arr.argmax(axis=0), arr.argmax(axis=1)
(8, array([2, 2, 2]), array([2, 2, 2]))
# 找出最小元素的索引
arr.argmin(), arr.argmin(axis=0), arr.argmin(axis=1)
(0, array([0, 0, 0]), array([0, 0, 0]))
隨機數np.random
主要介紹創建ndarray隨機數組以及隨機打亂順序、隨機選取元素等相關操作的方法。
創建隨機ndarray數組
創建隨機ndarray數組主要包含設置隨機種子、均勻分佈和正態分佈三部分內容,具體代碼如下所示。
- 設置隨機數種子
# 可以多次運行,觀察程序輸出結果是否一致
# 如果不設置隨機數種子,觀察多次運行輸出結果是否一致
np.random.seed(10)
a = np.random.rand(3, 3)
a
array([[0.77132064, 0.02075195, 0.63364823],
[0.74880388, 0.49850701, 0.22479665],
[0.19806286, 0.76053071, 0.16911084]])
- 均勻分佈
# 生成均勻分佈隨機數,隨機數取值範圍在[0, 1)之間
a = np.random.rand(3, 3)
a
array([[0.08833981, 0.68535982, 0.95339335],
[0.00394827, 0.51219226, 0.81262096],
[0.61252607, 0.72175532, 0.29187607]])
# 生成均勻分佈隨機數,指定隨機數取值範圍和數組形狀
a = np.random.uniform(low = -1.0, high = 1.0, size=(2,2))
a
array([[ 0.83554825, 0.42915157],
[ 0.08508874, -0.7156599 ]])
- 正態分佈
# 生成標準正態分佈隨機數
a = np.random.randn(3, 3)
a
array([[ 1.484537 , -1.07980489, -1.97772828],
[-1.7433723 , 0.26607016, 2.38496733],
[ 1.12369125, 1.67262221, 0.09914922]])
# 生成正態分佈隨機數,指定均值loc和方差scale
a = np.random.normal(loc = 1.0, scale = 1.0, size = (3,3))
a
array([[2.39799638, 0.72875201, 1.61320418],
[0.73268281, 0.45069099, 1.1327083 ],
[0.52385799, 2.30847308, 1.19501328]])
隨機打亂ndarray數組順序
- 隨機打亂1維ndarray數組順序,發現所有元素位置都被打亂了,代碼如下所示。
# 生成一維數組
a = np.arange(0, 30)
# 打亂一維數組順序
print('before random shuffle: ', a)
np.random.shuffle(a)
print('after random shuffle: ', a)
('before random shuffle: ', array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]))
('after random shuffle: ', array([10, 21, 26, 7, 0, 23, 2, 17, 18, 20, 12, 6, 9, 3, 25, 5, 13,
14, 24, 29, 1, 28, 11, 15, 27, 16, 19, 4, 22, 8]))
隨機打亂2維ndarray數組順序,發現只有行的順序被打亂了,列順序不變,代碼如下所示。
# 生成一維數組
a = np.arange(0, 30)
# 將一維數組轉化成2維數組
a = a.reshape(10, 3)
# 打亂一維數組順序
print('before random shuffle: \n{}'.format(a))
np.random.shuffle(a)
print('after random shuffle: \n{}'.format(a))
before random shuffle:
[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]
[12 13 14]
[15 16 17]
[18 19 20]
[21 22 23]
[24 25 26]
[27 28 29]]
after random shuffle:
[[15 16 17]
[12 13 14]
[27 28 29]
[ 3 4 5]
[ 9 10 11]
[21 22 23]
[18 19 20]
[ 0 1 2]
[ 6 7 8]
[24 25 26]]
隨機選取元素
# 隨機選取部分元素
a = np.arange(30)
b = np.random.choice(a, size=5)
b
array([ 0, 24, 12, 5, 4])
線性代數
線性代數(如矩陣乘法、矩陣分解、行列式以及其他方陣數學等)是任何數組庫的重要組成部分,Numpy中實現了線性代數中常用的各種操作,並形成了numpy.linalg線性代數相關的模塊。本節主要介紹如下函數:
diag
:以一維數組的形式返回方陣的對角線(或非對角線)元素,或將一維數組轉換爲方陣(非對角線元素爲0)。dot
:矩陣乘法。trace
:計算對角線元素的和。det
:計算矩陣行列式。eig
:計算方陣的特徵值和特徵向量。inv
:計算方陣的逆。
# 矩陣相乘
a = np.arange(12)
b = a.reshape([3, 4])
c = a.reshape([4, 3])
# 矩陣b的第二維大小,必須等於矩陣c的第一維大小
d = b.dot(c) # 等價於 np.dot(b, c)
print('a: \n{}'.format(a))
print('b: \n{}'.format(b))
print('c: \n{}'.format(c))
print('d: \n{}'.format(d))
a:
[ 0 1 2 3 4 5 6 7 8 9 10 11]
b:
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
c:
[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
d:
[[ 42 48 54]
[114 136 158]
[186 224 262]]
# numpy.linalg 中有一組標準的矩陣分解運算以及諸如求逆和行列式之類的東西
# np.linalg.diag 以一維數組的形式返回方陣的對角線(或非對角線)元素,
# 或將一維數組轉換爲方陣(非對角線元素爲0)
e = np.diag(d)
f = np.diag(e)
print('d: \n{}'.format(d))
print('e: \n{}'.format(e))
print('f: \n{}'.format(f))
d:
[[ 42 48 54]
[114 136 158]
[186 224 262]]
e:
[ 42 136 262]
f:
[[ 42 0 0]
[ 0 136 0]
[ 0 0 262]]
# trace, 計算對角線元素的和
g = np.trace(d)
g
440
# det,計算行列式
h = np.linalg.det(d)
h
1.3642420526593978e-11
# eig,計算特徵值和特徵向量
i = np.linalg.eig(d)
i
(array([4.36702561e+02, 3.29743887e+00, 3.13152204e-14]),
array([[ 0.17716392, 0.77712552, 0.40824829],
[ 0.5095763 , 0.07620532, -0.81649658],
[ 0.84198868, -0.62471488, 0.40824829]]))
# inv,計算方陣的逆
tmp = np.random.rand(3, 3)
j = np.linalg.inv(tmp)
j
array([[-0.59449952, 1.39735912, -0.06654123],
[ 1.56034184, -0.40734618, -0.48055062],
[ 0.10659811, -0.62164179, 1.30437759]])
Numpy保存和導入文件
文件讀寫
Numpy可以方便的進行文件讀寫,如下面這種格式的文本文件:
# 使用np.fromfile從文本文件'housing.data'讀入數據
# 這裏要設置參數sep = ' ',表示使用空白字符來分隔數據
# 空格或者回車都屬於空白字符,讀入的數據被轉化成1維數組
d = np.fromfile('./work/housing.data', sep = ' ')
d
array([6.320e-03, 1.800e+01, 2.310e+00, ..., 3.969e+02, 7.880e+00,
1.190e+01])
文件保存
Numpy提供了save和load接口,直接將數組保存成文件(保存爲.npy格式),或者從.npy文件中讀取數組。
# 產生隨機數組a
a = np.random.rand(3,3)
np.save('a.npy', a)
# 從磁盤文件'a.npy'讀入數組
b = np.load('a.npy')
# 檢查a和b的數值是否一樣
check = (a == b).all()
check
True
Numpy應用舉例
計算激活函數Sigmoid和ReLU
使用ndarray數組可以很方便的構建數學函數,並利用其底層的矢量計算能力快速實現計算。下面以神經網絡中比較常用激活函數Sigmoid和ReLU爲例,介紹代碼實現過程。
- 計算Sigmoid激活函數
- 計算ReLU激活函數
使用Numpy計算激活函數Sigmoid和ReLU的值,使用matplotlib畫出圖形,代碼如下所示。
# ReLU和Sigmoid激活函數示意圖
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.patches as patches
#設置圖片大小
plt.figure(figsize=(8, 3))
# x是1維數組,數組大小是從-10. 到10.的實數,每隔0.1取一個點
x = np.arange(-10, 10, 0.1)
# 計算 Sigmoid函數
s = 1.0 / (1 + np.exp(- x))
# 計算ReLU函數
y = np.clip(x, a_min = 0., a_max = None)
#########################################################
# 以下部分爲畫圖程序
# 設置兩個子圖窗口,將Sigmoid的函數圖像畫在左邊
f = plt.subplot(121)
# 畫出函數曲線
plt.plot(x, s, color='r')
# 添加文字說明
plt.text(-5., 0.9, r'$y=\sigma(x)$', fontsize=13)
# 設置座標軸格式
currentAxis=plt.gca()
currentAxis.xaxis.set_label_text('x', fontsize=15)
currentAxis.yaxis.set_label_text('y', fontsize=15)
# 將ReLU的函數圖像畫在左邊
f = plt.subplot(122)
# 畫出函數曲線
plt.plot(x, y, color='g')
# 添加文字說明
plt.text(-3.0, 9, r'$y=ReLU(x)$', fontsize=13)
# 設置座標軸格式
currentAxis=plt.gca()
currentAxis.xaxis.set_label_text('x', fontsize=15)
currentAxis.yaxis.set_label_text('y', fontsize=15)
plt.show()
圖像翻轉和裁剪
圖像是由像素點構成的矩陣,其數值可以用ndarray來表示。將上述介紹的操作用在圖像數據對應的ndarray上,可以很輕鬆的實現圖片的翻轉、裁剪和亮度調整,具體代碼和效果如下所示。
# 導入需要的包
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
# 讀入圖片
image = Image.open('./work/images/000000001584.jpg')
image = np.array(image)
# 查看數據形狀,其形狀是[H, W, 3],
# 其中H代表高度, W是寬度,3代表RGB三個通道
image.shape
(612, 612, 3)
# 原始圖片
plt.imshow(image)
<matplotlib.image.AxesImage at 0x7fefe4f56290>
# 垂直方向翻轉
# 這裏使用數組切片的方式來完成,
# 相當於將圖片最後一行挪到第一行,
# 倒數第二行挪到第二行,...,
# 第一行挪到倒數第一行
# 對於行指標,使用::-1來表示切片,
# 負數步長表示以最後一個元素爲起點,向左走尋找下一個點
# 對於列指標和RGB通道,僅使用:表示該維度不改變
image2 = image[::-1, :, :]
plt.imshow(image2)
<matplotlib.image.AxesImage at 0x7fefe4ecc850>
# 水平方向翻轉
image3 = image[:, ::-1, :]
plt.imshow(image3)
<matplotlib.image.AxesImage at 0x7fefe4e35f10>
# 保存圖片
im3 = Image.fromarray(image3)
im3.save('im3.jpg')
# 高度方向裁剪
H, W = image.shape[0], image.shape[1]
# 注意此處用整除,H_start必須爲整數
H1 = H // 2
H2 = H
image4 = image[H1:H2, :, :]
plt.imshow(image4)
<matplotlib.image.AxesImage at 0x7fefe4e2cc10>
# 寬度方向裁剪
W1 = W//6
W2 = W//3 * 2
image5 = image[:, W1:W2, :]
plt.imshow(image5)
<matplotlib.image.AxesImage at 0x7fefe4d2e050>
# 兩個方向同時裁剪
image5 = image[H1:H2, \
W1:W2, :]
plt.imshow(image5)
<matplotlib.image.AxesImage at 0x7fefe4d09b10>
# 調整亮度
image6 = image * 0.5
plt.imshow(image6.astype('uint8'))
<matplotlib.image.AxesImage at 0x7fefe4367fd0>
# 調整亮度
image7 = image * 2.0
# 由於圖片的RGB像素值必須在0-255之間,
# 此處使用np.clip進行數值裁剪
image7 = np.clip(image7, \
a_min=None, a_max=255.)
plt.imshow(image7.astype('uint8'))
<matplotlib.image.AxesImage at 0x7fefe42e4990>
#高度方向每隔一行取像素點
image8 = image[::2, :, :]
plt.imshow(image8)
<matplotlib.image.AxesImage at 0x7fefe4259e50>
#寬度方向每隔一列取像素點
image9 = image[:, ::2, :]
plt.imshow(image9)
<matplotlib.image.AxesImage at 0x7fefe4255510>
#間隔行列採樣,圖像尺寸會減半,清晰度變差
image10 = image[::2, ::2, :]
plt.imshow(image10)
image10.shape
(306, 306, 3)
作業1-7:使用numpy計算tanh激活函數
tanh是神經網絡中常用的一種激活函數,其定義如下:
請參照講義中Sigmoid激活函數的計算程序,用numpy實現tanh函數的計算,並畫出其函數曲線。
請用numpy寫出計算程序,並畫出tanh函數曲線圖,x的取值範圍設置爲[-10., 10.]。
作業1-8: 統計隨機生成矩陣中有多少個元素大於0
假設使用np.random.randn生成了隨機數構成的矩陣:
p = np.random.randn(10, 10)
請寫一段程序統計其中有多少個元素大於0?
提示:可以試下使用 q = (p > 0),觀察q是什麼的數據類型和元素的取值。