1. 程式人生 > >以np.concatenate為主題,談談numpy陣列按維度合併的問題

以np.concatenate為主題,談談numpy陣列按維度合併的問題

1.引言

最近在做多模態融合的影象問題,其中最需要解決的就是不同模態的影象用什麼方法進行融合,最簡單也最直觀的方法就是採用合併陣列的方法,將不同模態的影象合併為多通道進行處理。在一些論文中,比如《Deep Learning-Based Image Segmentation on Multimodal Medical Imaging》中,如圖1.1所示,論文中發現簡單的concat 成多通道進行處理反而會比經過一部分網路提取特徵後再融合效果更好。不過不同的情況需要具體分析,在《FusionNet: Incorporating Shape and Texture for Abnormality Detection in 3D Abdominal CT Scans》中,文章進行了多種組合的實驗(不是模態融合,而是圖片和mask的組合),結果發現某一種組合的效果最好。

 

 

 

圖1.1 文章中提到的融合網路結構以及效果

 

 

不過總的來說,能夠使用concat進行合併陣列肯定是快速而有效的一種模態融合方法。

2.簡要解析np.concatente官方文件

參見https://docs.scipy.org/doc/numpy-1.15.0/reference/generated/numpy.concatenate.html

numpy.concatenate((a1a2...)axis=0out=None)

Join a sequence of arrays along an existing axis.

Parameters:
a1, a2, … : sequence of array_like

The arrays must have the same shape, except in the dimension corresponding to axis (the first, by default).

axis : int, optional

The axis along which the arrays will be joined. If axis is None, arrays are flattened before use. Default is 0.

out : ndarray, optional

If provided, the destination to place the result. The shape must be correct, matching that of what concatenate would have returned if no out argument were specified.

Returns:
res : ndarray

The concatenated array.

concatenate中含有兩個引數,第一個引數是一個元組,元組裡填入你想合併的陣列,第二個引數是axis軸,第一個引數沒什麼好說的,主要想談第二個引數。

另外要提的是官方提示,這個對我來說沒什麼用。

注意:當要串聯的一個或多個數組為MaskedArray時,此函式將返回MaskedArray物件而不是ndarray,但不會保留輸入掩碼。 如果需要使用MaskedArray作為輸入,請改用MaskedArray模組中的ma.concatenate函式。

正常的陣列例子

>>> a = np.array([[1, 2], [3, 4]])
>>> b = np.array([[5, 6]])
>>> np.concatenate((a, b), axis=0)
array([[1, 2],
       [3, 4],
       [5, 6]])
>>> np.concatenate((a, b.T), axis=1)
array([[1, 2, 5],
       [3, 4, 6]])
>>> np.concatenate((a, b), axis=None)
array([1, 2, 3, 4, 5, 6])

 

 陣列是MaskedArray時的例子,此函式將不會保留MaskedArray輸入的掩碼,要保留的話要用ma那個函式。

>>> a = np.ma.arange(3)
>>> a[1] = np.ma.masked
>>> b = np.arange(2, 5)
>>> a
masked_array(data = [0 -- 2],
             mask = [False  True False],
       fill_value = 999999)
>>> b
array([2, 3, 4])
>>> np.concatenate([a, b])
masked_array(data = [0 1 2 2 3 4],
             mask = False,
       fill_value = 999999)
>>> np.ma.concatenate([a, b])
masked_array(data = [0 -- 2 2 3 4],
             mask = [False  True False False False False],
       fill_value = 999999)

  

3.axis的軸到底指的是什麼

網上大多介紹的是一維陣列和二維陣列,但是很少提到高維陣列的情況,

比如說當axis=0時,這時候就是np.concatenate指的是水平合併陣列,當axi=1時,指的是垂直方向合併陣列,舉個例子:

定義兩個陣列:

a
array([0, 1, 2],
       [3, 4, 5],
       [6, 7, 8])
b = a*2
b
array([ 0, 2, 4],
       [ 6, 8, 10],
       [12, 14, 16])

  下面進行合併:

np.hstack((a,b))
array([ 0, 1, 2, 0, 2, 4],
       [ 3, 4, 5, 6, 8, 10],
       [ 6, 7, 8, 12, 14, 16])

np.concatenate((a,b),axis=1)
array([ 0, 1, 2, 0, 2, 4],
       [ 3, 4, 5, 6, 8, 10],
       [ 6, 7, 8, 12, 14, 16])
np.vstack((a,b))
array([ 0, 1, 2],
       [ 3, 4, 5],
       [ 6, 7, 8],
       [ 0, 2, 4],
       [ 6, 8, 10],
       [12, 14, 16])

np.concatenate((a,b),axis=0)
array([ 0, 1, 2],
       [ 3, 4, 5],
       [ 6, 7, 8],
       [ 0, 2, 4],
       [ 6, 8, 10],
       [12, 14, 16])

 兩種方式分別和np中的hstack以及vstack的合併陣列的結果相同,那麼concatenate存在的意義到底是什麼呢,就在於它可以進行更高維度的數組合並。

就對我的問題而言,我要對兩種模態的3d切片資料進行合併,兩個資料的shape均為(10,1,128,128),如果我使用axis=1,那麼不是進行垂直合併,而是選擇了第二維度進行合併,比如說下面這個例子,最終輸出的結果就是一個(10,2,128,128)的陣列。

#coding=utf-8
import numpy as np

np.random.seed(0) 
a = np.random.randint(0, 255, (10, 1, 128, 128))
b = np.random.randint(0, 255, (10, 1, 128,128))
ab = np.concatenate((a,b),axis = 1)
print('ab的維度為 = \n {}'.format(ab.shape))

ab的維度為 = (10, 2, 128, 128)

 

這就一目瞭然了,原來np.concatenate並不僅僅是水平和垂直合併,而是多個維度的合併,axis軸的選擇其實就是對某一個維度的選擇。


那麼進行資料融合的適合就方便多了,不過要解決先讓資料進入網路後再提取特徵進行fusion訓練就是另一個問題了,我們下次再考慮。

&n