關於pytorch語義分割二分類問題的兩種做法

2021-10-20 16:34:58 字數 3396 閱讀 6787

即網路的輸出output為 [batch_size, 1, height, width] 形狀。其中batch_szie為批量大小,1表示輸出乙個通道,heightwidth與輸入影象的高和寬保持一致。

在訓練時,輸出通道數是 1,網路得到的output包含的數值是任意的數。給定的target,是乙個單通道標籤圖,數值只有 0 和 1 這兩種。為了讓網路輸出output不斷逼近這個標籤,首先會讓output經過乙個sigmoid函式,使其數值歸一化到[0, 1],得到output1,然後讓這個output1target進行交叉熵計算,得到損失值,反向傳播更新網路權重。最終,網路經過學習,會使得output1逼近target

訓練結束後,網路已經具備讓輸出的output經過轉換從而逼近target的能力。首先將輸出的output通過sigmoid函式,然後取乙個閾值(一般設定為0.5),大於閾值則取1反之則取0,從而得到**圖predict。後續則是一些評估相關的計算。

在這個過程中,訓練的損失函式為二進位制交叉熵損失函式,然後根據輸出是否用到了sigmoid有兩種可選的pytorch實現方式:

python

output = net(input)  # net的最後一層沒有使用sigmoid

loss_func1 = torch.nn.bcewithlogitsloss()

loss = loss_func1(output, target)

當網路最後一層沒有使用sigmoid時,需要使用torch.nn.bcewithlogitsloss(),顧名思義,在這個函式中,拿到output首先會做乙個sigmoid操作,再進行二進位制交叉熵計算。上面的操作等價於

python

output = net(input)  # net的最後一層沒有使用sigmoid

output = f.sigmoid(output)

loss_func1 = torch.nn.bcewithloss()

loss = loss_func1(output, target)

當然,你也可以在網路最後一層加上sigmoid操作。從而省去第二行的**(在**時也可以省去)。

在**試時,可用下面的**實現**圖的生成

python

output = net(input)  # net的最後一層沒有使用sigmoid

output = f.sigmoid(output)

predict = torch.where(output>0.5,torch.ones_like(output),torch.zeros_like(output))

...

即大於0.5的記為1,小於0.5記為0。

即網路的輸出output為 [batch_size, num_class, height, width] 形狀。其中batch_szie為批量大小,num_class表示輸出的通道數與分類數量一致,heightwidth與輸入影象的高和寬保持一致。

在訓練時,輸出通道數是num_class(這裡取2),網路得到的output包含的數值是任意的數。給定的target,是乙個單通道標籤圖,數值只有 0 和 1 這兩種。為了讓網路輸出output不斷逼近這個標籤,首先會讓output經過乙個softmax函式,使其數值歸一化到[0, 1],得到output1,在各通道中,這個數值加起來會等於1。對於target他是乙個單通道圖,首先使用onehot編碼,轉換成num_class個通道的影象,每個通道中的取值是根據單通道中的取值計算出來的,例如單通道中的第乙個畫素取值為1(0<= 1 <=num_class-1,這裡num_class=2),那麼onehot編碼後,在第乙個畫素的位置上,兩個通道的取值分別為0,1。也就是說畫素的取值決定了對應序號的通道取1,其他的通道取0,這個非常關鍵。上面的操作執行完後得到target1,讓這個output1target1進行交叉熵計算,得到損失值,反向傳播更新網路權重。最終,網路經過學習,會使得output1逼近target1(在各通道層面上)。

訓練結束後,網路已經具備讓輸出的output經過轉換從而逼近target的能力。計算output中各通道每乙個畫素位置上,取值最大的那個對應的通道序號,從而得到**圖predict。後續則是一些評估相關的計算。

在這個過程中,則可以使用交叉熵損失函式:

python

output = net(input)  # net的最後一層沒有使用sigmoid

loss_func = torch.nn.crossentropyloss()

loss = loss_func(output, target)

根據前面的分析,我們知道,正常的output是 [batch_size, num_class, height, width]形狀的,而target是[batch_size, height, width]形狀的,需要按照上面的分析進行轉換才可以計算交叉熵,而在pytorch中,我們不需要進一步做這個處理,直接使用就可以了。

在**試時,使用下面的**實現**圖的生成

python

output = net(input)  # net的最後一層沒有使用sigmoid

predict = output.argmax(dim=1)

...

即得到輸出後,在通道方向上找出最大值所在的索引號。

總的來說,我覺得第二種方式更值得推廣,一方面不用考慮閾值的選取問題;另一方面,該方法同樣適用於多類別的語義分割任務,通用性更強。

[1][2]

原帖:

矩形分割(二分)

描述 平面上有乙個大矩形,其左下角座標 0,0 右上角座標 r,r 大矩形內部包含一些小矩形,小矩形都平行於座標軸且互不重疊。所有矩形的頂點都是整點。要求畫一根平行於y軸的直線x k k是整數 使得這些小矩形落在直線左邊的面積必須大於等於落在右邊的面積,且兩邊面積之差最小。並且,要使得大矩形在直線左...

分割繩子(二分)

時間限制 1 sec 記憶體限制 128 mb 題目描述 現有n條繩子,它們的長度分別為l1,l2,ln,如果從它們中切割出k條長度相同的繩子,這k條繩子每條最長能有多長?輸入共有兩行,第一行包含兩個正整數n和k,用乙個空格分隔 第二行包含n個數,依次表示n條繩子的長度,兩數間用乙個空格分隔。每條繩...

分割繩子(二分)

現在有n 1 n 1000 條繩子,他們的長度分別為l1,l2,ln 1 li 10000 如果從他們中切割出k 1 k 1000 條長度相同的繩子,這k條繩子每條最長能多長?收起共有兩行,第一行包含兩個正整數n和k,用乙個空格分割 第二行包含n個數,一次表示n條繩子的長度,兩數間用乙個空格分隔,每...