交叉熵反向傳播推導(dǎo)及pytorch實現(xiàn)

本文主要參考反向傳播之一:softmax函數(shù),添加相應(yīng)的pytorch的實現(xiàn)

softmax函數(shù)

定義及簡單實現(xiàn)

記輸入為X={x_1,x_2,\dots,x_n},標(biāo)簽為Y=y_1, y_2, \dots, y_n, 通過softmax之后的輸出為\hat Y={\hat y_1, \hat y_2,\dots, \hat y_n},則:
\hat Y=softxmax(X)
其中,\hat y_i=\frac{e^{x_i}}{\sum_{j=1}^ne^{x_j}}
pytorch庫函數(shù)和手動實現(xiàn):

def seed_torch(seed=1234):
    random.seed(seed)
    os.environ['PYTHONHASHSEED'] = str(seed)
    np.random.seed(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)  # if you are using multi-GPU.
    torch.backends.cudnn.benchmark = False
    torch.backends.cudnn.deterministic = True
    torch.backends.cudnn.enabled = False

def softmax(x, dim=1):
    x=x-torch.max(x, dim=dim)[0].unsqueeze(dim=dim) # 防止溢出
    res = torch.exp(x) / torch.sum(torch.exp(x), dim=dim).unsqueeze(dim=dim)
    return res
if __name__ == '__main__':
    seed_torch(1234)
    x=torch.rand(4,7, requires_grad=True)

    print(torch.softmax(x,dim=-1))
    print(softmax(x, dim=-1))

求導(dǎo)推導(dǎo)\frac{\partial y_i}{\partial x_j}

當(dāng)i=j

當(dāng)i≠j

綜上:
\frac{\partial Y}{\partial X}=diag(Y)-Y^TY
其中,diag(Y)為以Y元素為對角線元素構(gòu)造的矩陣
公式推導(dǎo)來自:https://zhuanlan.zhihu.com/p/37740860。圖中的y應(yīng)為\hat y

交叉熵

計算公式

L = -\sum_{k=1}^{C}y_kln\hat{y}_k
說明:

  • C表示分類任務(wù)中的類別數(shù)
  • y表示的該樣本對應(yīng)的標(biāo)簽,是一個C維的向量,一般使用one-hot編碼,y_k表示其第k維的值,為0或者1
  • \hat{y}表示模型計算出的分類概率向量,C維,每一維表示預(yù)測得到該類的概率,即\hat{y}_k,由softmax函數(shù)計算得到

pytorch 實現(xiàn):

    seed_torch(1234)
    x=torch.rand(4,7, requires_grad=True)  # 4個樣本,共7類
    y=torch.LongTensor([1,3,5,0]) # 對應(yīng)的標(biāo)簽
    criterion = torch.nn.CrossEntropyLoss()  # pytroch庫
    out = criterion(x,y)
    print(out)
   # 自己實現(xiàn)
    gt = torch.zeros(4,7).scatter(1, y.view(4,1),1)  # 生成one-hot標(biāo)簽,scatter的用法可參考jianshu.com/p/b4e9fd4048f4
    loss = -(torch.log(softmax(x, dim=-1)) * gt).sum() / 4  # 對樣本求平均
    print(loss)

輸出:


反向傳播

\begin{align} \frac{\partial L}{\partial x_k}&=\sum_{i=1}^{C}\frac{\partial L}{\partial \hat{y}_i} \frac{\partial \hat{y}_i}{\partial x_k}& \\ &=-\sum_{i=1}^C \frac{\partial}{\partial \hat{y}_i} (y_iln\hat{y}_i)\cdot\frac{\partial \hat{y}_i}{\partial x_k}& \\ &=-\sum_{i=1}^C \frac{y_i}{\hat{y}_i}\cdot \frac{\partial \hat{y}_i}{\partial x_k}&\\ &=-\frac{y_k}{\hat y_k} \hat y_k(1-\hat y_k) + \sum_{i=1, i\ne k}^C\frac{y_i}{\hat y_i}\hat y_i \hat y_k& \\ &=-y_k + y_k\hat y_k +\sum_{i=1, i\ne k}^Cy_i\hat y_k &\\ &=-y_k+\sum_{i=1}^Cy_i\hat y_k &\\ &=-y_k+\hat y_k\sum_{i=1}^Cy_i &\\ &=\hat y_k - y_k \end{align}
所以:
\frac{\partial L}{\partial X}=\hat Y-Y

pytorch實現(xiàn)

    seed_torch(1234)
    x=torch.rand(4,7)  # 4個樣本,共7類
    x1=x.clone()  # 4個樣本,共7類
    x2=x.clone()  # 4個樣本,共7類
    x1.requires_grad=True
    x2.requires_grad=True
    y=torch.LongTensor([1,3,5,0]) # 對應(yīng)的標(biāo)簽
    criterion = torch.nn.CrossEntropyLoss()
    out = criterion(x1,y)
    out.backward()
    print('pytorch庫 loss:', out, 'grad:', x1.grad)

    gt = torch.zeros(4,7).scatter(1, y.view(4,1),1)
    loss = -(torch.log(softmax(x2, dim=-1)) * gt).sum() / 4  # 對樣本求平均
    loss.backward()
    print('手動實現(xiàn) loss:', loss, 'grad:', x2.grad)

    eta = (torch.softmax(x, dim=-1) - gt) / 4
    print('直接計算 grad:', eta)

輸出:


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容