Как да използвам обратно разпространение със самодефинирана загуба в pytorch?

Опитвам се да внедря сиамска мрежа със загуба на класиране между две изображения. Ако дефинирам собствената си загуба, ще мога ли да направя стъпката на обратно разпространение, както следва? Когато го стартирам, понякога ми се струва, че дава същите резултати, които дава единичната мрежа.

with torch.set_grad_enabled(phase == 'train'):
    outputs1 = model(inputs1)
    outputs2 = model(inputs2)
    preds1 = outputs1;
    preds2 = outputs2;

    alpha = 0.02;
    w_r = torch.tensor(1).cuda(async=True);

    y_i, y_j, predy_i, predy_j = labels1,labels2,outputs1,outputs2;
    batchRankLoss =  torch.tensor([max(0,alpha - delta(y_i[i], y_j[i])*predy_i[i] - predy_j[i])) for i in range(batchSize)],dtype = torch.float)
    rankLossPrev = torch.mean(batchRankLoss)                                             
    rankLoss = Variable(rankLossPrev,requires_grad=True)

    loss1 = criterion(outputs1, labels1)
    loss2 = criterion(outputs2, labels2)


    #total loss = loss1 + loss2 + w_r*rankLoss
    totalLoss = torch.add(loss1,loss2)
    w_r = w_r.type(torch.LongTensor)
    rankLossPrev = rankLossPrev.type(torch.LongTensor)
    mult = torch.mul(w_r.type(torch.LongTensor),rankLossPrev).type(torch.FloatTensor)
    totalLoss = torch.add(totalLoss,mult.cuda(async = True));

     # backward + optimize only if in training phase
         if phase == 'train':
            totalLoss.backward()
            optimizer.step()

            running_loss += totalLoss.item() * inputs1.size(0)

person ce1    schedule 28.08.2018    source източник


Отговори (2)


Имате няколко реда, където генерирате нови тензори от конструктор или преобразуване към друг тип данни. Когато направите това, вие прекъсвате веригата от операции, чрез които искате командата backwards() да се разграничи.

Това кастинг прекъсва графа, тъй като кастингът е недиференцируем:

w_r = w_r.type(torch.LongTensor)

Изграждането на тензор от конструктор ще изключи графиката:

batchRankLoss = torch.tensor([max(0,alpha - delta(y_i[i], y_j[i])*predy_i[i] - predy_j[i])) for i in range(batchSize)],dtype = torch.float)

От документите, опаковането на Tensor в променлива ще зададе grad_fn на None (също прекъсване на връзката с графиката):

rankLoss = Variable(rankLossPrev,requires_grad=True)

Ако приемем, че вашата critereon функция е диференцируема, тогава градиентите в момента текат назад само през loss1 и loss2. Вашите други градиенти ще текат само до mult, преди да бъдат спрени от извикване на type(). Това е в съответствие с вашето наблюдение, че вашата персонализирана загуба не променя изхода на вашата невронна мрежа.

За да позволите на градиентите да текат назад през вашата персонализирана загуба, ще трябва да кодирате същата логика, като същевременно избягвате type() прехвърляния и изчислявате rankLoss без да използвате разбиране на списък.

person protagonist    schedule 29.08.2018

   rank_loss = torch.mean([torch.max(0,alpha - delta(y_i[i], y_j[i])*predy_i[i] - predy_j[i])) for i in range(batchSize)], dim=0)
   w_r = 1.0
   loss1 = criterion(outputs1, labels1)
   loss2 = criterion(outputs2, labels2)
   total_loss = loss1 + loss2 + w_r  * rank_loss 
   if phase == 'train':
       total_loss .backward()
       optimizer.step()

Не е нужно да създавате тензор отново и отново. Ако имате различни тегла за всяка загуба и теглата са просто константи, можете просто да напишете:

total_loss = weight_1 * loss1 + weight_2 * loss2 + weight_3  * rank_loss

Това така или иначе е неподлежаща на обучение константа, няма смисъл да създавате променлива A и да задавате requires_grad на True, защото теглата са само константи. Моля, надстройте до pytorch 0.4.1, в който не е нужно да обвивате всичко с Variable

person weiyixie    schedule 29.08.2018