Вычисление потери функции предсказаний с помощью pytorch

У меня есть сверточная нейронная сеть, которая предсказывает 3 величины: Ux, Uy и P. Это скорость x, скорость y и поле давления. Все они представляют собой 2D-массивы размером [100,60], а размер моего пакета - 10.

Я хочу вычислить потери и обновить сеть, вычислив CURL предсказанной скорости с CURL целевой скорости. У меня есть функция, которая делает это: v = curl (Ux_pred, Uy_pred). Учитывая прогнозируемые Ux и Uy, я хочу вычислить потери, сравнив их с имеющимися у меня целевыми точками: true_curl = curl (Ux_true, Uy_true) - я уже вычислил истинное значение curl и добавил это к моим данным Y, как четвертый канал.

Однако я хочу, чтобы моя сеть предсказывала только Ux, Uy и P. Я хочу, чтобы мои параметры NN обновлялись на основе ПОТЕРИ завитков, чтобы повысить точность Ux и Uy. Потеря локона должна выражаться в единицах Ux и Uy. Я пытался сделать это с помощью автограда Pytorch и уже читал много похожих вопросов, но я просто не могу заставить его работать. Это мой код на данный момент:

        print("pred_Curl shape:", np.shape(pred_curl))
        print("pred_Ux shape:", np.shape(pred[:,0,:,:]))
        print("pred_Uy shape:", np.shape(pred[:,1,:,:]))
        true_curl = torch.from_numpy(y[:,3,:,:]) # not sure where to use the true curl?

        pred_curl = Variable(pred_curl, requires_grad=True)
        
        pred_ux = pred[:,0,:,:]
        pred_uy = pred[:,1,:,:]

        pred_ux = Variable(pred_ux, requires_grad=True)
        pred_uy = Variable(pred_uy, requires_grad=True)

        grad_tensor = torch.autograd.grad(outputs=pred_curl, inputs=(pred_ux, pred_uy), 
                       grad_outputs=torch.ones_like(pred_curl), 
                       retain_graph=True,create_graph=True)

        loss = torch.sum(grad_tensor)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

Это дает следующий результат:

pred_Curl shape: torch.Size([10, 100, 60])
pred_Ux shape: torch.Size([10, 100, 60])
pred_Uy shape: torch.Size([10, 100, 60])

RuntimeError: One of the differentiated Tensors appears to not have been used in the graph. 
Set allow_unused=True if this is the desired behavior.

Любая помощь будет оценена по достоинству!

Изменить: вот моя функция завитка:

    def discrete_curl(self,x,y,new_arr):
            for m in range(100):
                for n in range(60):
                    if n <= 58:
                        if m <= 98:
                            if x[m,n] != 0 and y[m,n] != 0:
                                new_arr[m,n] = ((y[m+1,n] - y[m-1,n]) / 2*1) - ((x[m,n+1] - x[m,n-1]) / 2*1)
            return new_arr 

Где x и y - это Ux ad Uy, а new_arr - это результат curl.


person user3611    schedule 19.05.2021    source источник
comment
Вы спрашиваете, какая функция потерь будет подходящей? Я не совсем понял ваш третий абзац.   -  person GoodDeeds    schedule 19.05.2021
comment
Я спрашиваю, как вычислить потерю завитка на основе данных, используемых в нейронной сети: это Ux и Uy, чтобы оптимизатор соответствующим образом скорректировал параметры модели!   -  person user3611    schedule 19.05.2021
comment
Правильно ли я, что для правильного предсказания Ux и Uy они должны быть равны Ux_true и Uy_true? Если это так, я думаю, вам нужно выбрать подходящую метрику, по которой вы хотите сравнивать истинные и прогнозируемые локоны. Например, потеря MSE минимизирует возведенную в квадрат норму L2 между предсказанием и наземной истиной. Когда у вас есть потери, PyTorch может вычислить производные, распространить градиенты в обратном направлении и обновить веса сети, чтобы сделать Ux и Uy ближе к Ux_true и Uy_true.   -  person GoodDeeds    schedule 19.05.2021
comment
Ага, я не могу просто посчитать потерю без автограда, не работает. Мне нужно дифференцировать локон по интересующим переменным: Ux и Uy. И вот здесь я сталкиваюсь с проблемами   -  person user3611    schedule 20.05.2021
comment
Мне непонятно, почему вы вручную пытаетесь вычислить градиенты. Например, вы можете сделать loss = torch.nn.functional.mse_loss(pred_curl, true_curl) и оставить остальную часть кода как есть. Дифференциация будет сделана автоматически, когда вы позвоните loss.backward(). По какой-либо причине, которая не сработает в вашем случае? (Кстати, я предполагаю, что локон является кусочно дифференцируемой функцией. Если нет, это усложняет задачу.)   -  person GoodDeeds    schedule 20.05.2021
comment
Когда я пытаюсь просто сделать это, я получаю эту ошибку: RuntimeError: элемент 0 переменных не требует grad и не имеет grad_fn. Кроме того, я добавил свою функцию curl выше.   -  person user3611    schedule 20.05.2021


Ответы (1)


Вы можете попробовать что-то вроде этого:

def discrete_curl(self, pred):
        new_arr = torch.zeros((pred.shape[0],100,60))
        for pred_idx in range(pred.shape[0]):
            for m in range(100):
                for n in range(60):
                    if n <= 58:
                        if m <= 98:
                            if pred[pred_idx,0,m,n] != 0 and pred[pred_idx,1,m,n] != 0:
                                new_arr[pred_idx,m,n] = ((pred[pred_idx,1,m+1,n] - pred[pred_idx,1,m-1,n]) / 2*1) - ((pred[pred_idx,0,m,n+1] - pred[pred_idx,0,m,n-1]) / 2*1)
        return new_arr 

pred_curl = discrete_curl(pred)
true_curl = torch.from_numpy(y[:,3,:,:])
loss = torch.nn.functional.mse_loss(pred_curl, true_curl)
optimizer.zero_grad()
loss.backward()
optimizer.step()

Я думаю, что вычисление curl можно оптимизировать, но я старался по большей части придерживаться вашей структуры.

person GoodDeeds    schedule 20.05.2021
comment
Спасибо. Это дает мне следующую ошибку, которую я пока не могу решить: RuntimeError: листовая переменная была перемещена во внутреннюю часть графа. - person user3611; 21.05.2021
comment
@ user3611 Извините, а можно попробовать удалить requires_grad=True в объявлении new_arr? - person GoodDeeds; 21.05.2021
comment
Спасибо. Когда я это делаю, он бежит, но потери остаются «нан». - person user3611; 21.05.2021
comment
@ user3611 Можете ли вы поставить torch.autograd.set_detect_anomaly(True) в начале вашего скрипта и проверить результат? Он должен подсказать, что вызывает нан. Возможно, это может быть связано с этим блоком кода, но также может быть связано с другими причинами, такими как данные, гиперпараметры и т. Д. - person GoodDeeds; 21.05.2021
comment
Спасибо. Я уже преодолел эту ошибку, и она работает. Однако это не работает должным образом. Это не обновление таким образом, чтобы уменьшить потерю между прогнозируемым и реальным завитком. Убыток остается фиксированным. - person user3611; 21.05.2021
comment
@ user3611 Не могли бы вы предоставить более подробную информацию? Если это не связано с этим ответом, возможно, лучше создать новый пост. - person GoodDeeds; 22.05.2021