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

  • 2019 年 10 月 29 日
  • 筆記

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訓練就是另一個問題了,我們下次再考慮。