玩過深度學習圖像處理的都知道,對於一張分辨率超大的圖片,我們往往不會采取直接壓平讀入的方式喂入神經網絡,而是將它切成一小塊一小塊的去讀,這樣的好處就是可以加快讀取速度並且減少內存的占用。就拿醫學圖像處理來說吧,醫學CT圖像一般都是比較大的,一張圖片就可能達到500MB+,有的甚至超過1GB,下面是切過的一張已經被各種壓縮過的肝臟CT圖像的一角。
我們可以看到它的像素仍有5210*4200之多,如果直接把這樣一張圖片壓平,將會得到一個5210*4200=21882000維的tensor,將這樣一個上千萬維的數據直接喂入神經網絡,我不知道性能特別特別好的電腦能不能撐起來,反正我的電腦是肯定崩潰。那么如何處理這樣圖片呢?回到我們的標題----索引和切片。通過切片的方式我們可以把這張圖片分成若干28*28(或者其他合適分辨率)的小圖,分批次將這張圖喂入神經網絡,可想而知會取得不錯的效果。接下來就記錄幾種索引切片的方式。
方式1:通過連續的[ ]
這種方式在各種編程語言中都很常見,即數組的索引,但是這種方式只能取到某一具體維度的數值,不能隨心所欲的固定間隔或者非固定間隔的切片
a = tf.ones([1,5,5,3]) print(a[0][0]) print(a[0][0][0]) print(a[0][0][0][2])
方式2:通過[ , , ,……]
這種方式其實是numpy對方式1的一種在可讀性方面的優化,和方式1相比,可讀性明顯提高
a = tf.random.normal([4,28,28,3]) print(a[1].shape) print(a[1,2].shape) print(a[1,2,3].shape) print(a[1,2,3,2].shape)
方式3:一維tensor可通過[ :]
這種方式也是python中比較常用的數組切片方式,切片范圍[ A:B)
a=tf.range(10) print(a) print(a[-1:]) print(a[-2:]) print(a[:2]) print(a[:-1])
方式4:對於多維tensor可通過[ ,:,:,:……]
相對前面幾種切片方式都更加豐富,也可以完成多樣的切片(跳過某一維度)start:end
a = tf.random.normal([4,28,28,3]) print(a[0,:,:,:].shape) print(a[0,1,:,:].shape) print(a[:,:,:,0].shape) print(a[:,:,:,2].shape) print(a[:,0,:,:].shape)
方式5:隔行采樣[ : : ,: : ,: : ,……]
通過增加了一個:,使用方式start:end:step進行間隔采樣(::step代表從最開始到最末尾以步長step間隔采樣)
a = tf.random.normal([4,28,28,3]) print(a[:,0:28:2,0:28:2,:].shape) print(a[:,:14,:14,:].shape) print(a[:,14:,14:,:].shape) print(a[:,::2,::2,:].shape)
注:若step<0則倒序采樣
方式6:用…進行采樣
...可以代替連續的:,增強代碼的易書寫性和可讀性
a = tf.random.normal([2,4,28,28,3]) print(a[0,:,:,:,:].shape) print(a[0,...].shape) print(a[:,:,:,:,0].shape) print(a[...,0].shape) print(a[0,...,2].shape) print(a[1,0,...,0].shape)
方式6:selective indexing
使用tf.gather、tf.gather_nd、tf.boolean_mask進行隨機采樣
(1)tf.gather(在某一維度指定index)
# 下面的tensor即表示,4個班級,每個班級35名學生,每個學生8門課的成績 a = tf.random.normal([4,35,8]) # axis表示維度,indices表示在axis維度上要取數據的索引 print(tf.gather(a,axis=0,indices=[2,3]).shape) # 可理解為取第2、3個班級的學生成績,同a[2:4].shape print(tf.gather(a,axis=0,indices=[2,1,3,0]).shape) # 可理解為依次取第2、1、3、0個班級的學生成績 print(tf.gather(a,axis=1,indices=[2,3,7,9,16]).shape) # 可理解為取所有班級第2,3,7,9,16個學生的成績 print(tf.gather(a,axis=2,indices=[2,3,7]).shape) # 可理解為取所有班級所有學生第2,3,7門課的成績
(2)tf.gather_nd(在多個維度指定index)
a = tf.random.normal([4,35,8]) # axis表示維度,indices表示在axis維度上要取數據的索引 print(tf.gather_nd(a,[0]).shape) # 可理解為取0號班級的所有成績 print(tf.gather_nd(a,[0,1]).shape) # 可理解為取0號班級1號學生的成績 print(tf.gather_nd(a,[0,1,2]).shape) # 可理解為取0號班級1號學生的第2門課成績 print(tf.gather_nd(a,[[0,0],[1,1]]).shape) # 可理解為取0號班級0號學生和1號班級1號學生的成績 print(tf.gather_nd(a,[[0,0],[1,1],[2,2]]).shape) # 可理解為取0號班級0號學生、1號班級1號學生、2號班級2號學生的成績 print(tf.gather_nd(a,[[0,0,0],[1,1,1],[2,2,2]]).shape) # 可理解為0班0學0課,1班1學1課,2班2學2課的成績 print(tf.gather_nd(a,[[[0,0,0],[1,1,1],[2,2,2]]]).shape) # shape與上不同
(3)tf.boolean_mask(通過True和False的方式選擇數據)
a = tf.random.normal([4,28,28,3]) print(tf.boolean_mask(a,mask=[True,True,False,False]).shape) print(tf.boolean_mask(a,mask=[True,True,False],axis=3).shape) a = tf.ones([2,3,4]) print(tf.boolean_mask(a,mask=[[True,False,False],[False,True,True]]))