2017-12-05 27 views
1

음악 생성을위한 자동 인코딩을 개발하려고합니다. 그 목적을 추구하면서 나는 음악적 관계를 포착하는 손실 함수를 개발하려고 시도하고있다.음악 인코딩을위한 스파이럴 손실 기능

나의 현재 아이디어는 시스템이 다른 옥타브에서 같은 음을 예측하면 음이 틀렸을 때보다 손실이 작아야한다는 'Spiral'loss function입니다. 또한 B 및 D에서 C와 같은 정확한 음표에 가까운 음표는 작은 손실을 가져야합니다. 개념적으로 이것은 코일 또는 나선형상의 두 점 사이의 거리를 찾는 것으로 생각할 수 있습니다. 즉, 서로 다른 옥타브에있는 동일한 음표가 코일에 접하는 선을 따라 놓이지 만 루프 거리만큼 분리됩니다.

나는 PyTorch에서 일하고 있는데, 나의 입력 표현은 36 x 36 by Tensor이고, 행은 음표 (MIDI 범위 48:84, 피아노의 중간 3 옥타브)를 나타내고 열은 시간 단계 (1 열 = 1/100 초). 행렬의 값은 0 또는 1이며 특정 시간에 메모가 켜져 있음을 나타냅니다.

def SpiralLoss(): 
    def spiral_loss(input, output): 
     loss = Variable(torch.FloatTensor([0])) 
     d = 5 
     r = 10 
     for i in xrange(input.size()[0]): 
      for j in xrange(input.size()[3]): 
       # take along the 1 axis because it's a column vector 
       inval, inind = torch.max(input[i, :, :, j], 1) 
       outval, outind = torch.max(output[i, :, :, j], 1) 
       note_loss = (r*30*(inind%12 - outind%12)).float() 
       octave_loss = (d*(inind/12 - outind/12)).float() 
       loss += torch.sqrt(torch.pow(note_loss, 2) + torch.pow(octave_loss, 2)) 
     return loss 
    return spiral_loss 

이 손실 문제는 최대 함수를 미분되지 않는 것입니다 :

여기 손실의 내 현재의 구현입니다. 이 손실을 차별화 할 수있는 방법을 생각할 수 없으며 누군가가 아이디어 나 제안을 갖고 있는지 궁금해하고있었습니다.

내가이 위치와 같은 게시물에 적합한 지 확실하지 않으므로 그렇지 않은 경우 더 나은 위치를 향한 어떤 포인터에 대해서도 고맙게 생각합니다.

감사합니다.

+0

입출력의 4 차원이 무엇인지 설명해 주시겠습니까? – McLawrence

+0

예! NxCxHxW. 나는 미디 피아노 롤 표현으로 작업하고 있습니다. N은 일괄 처리의 수이고, C는 길쌈 레이어와 함께 사용하기위한 채널입니다 (본인의 경우 1). H는 미디 노트 치수이고 W는 시간 (피아노 롤의 높이와 너비)입니다 – bgenchel

+0

아 좋아요. 당신이 시도해 볼 수있는 하나의 가능한 솔루션을 게시하고 그것이 작동하는지 알려주세요 :) – McLawrence

답변

1

여기에서 최대 값을 얻는 것은 차별성 때문에 문제가되는 것이 아닙니다. 최대 출력 만 사용하고 올바른 위치에 있으면 잘못된 위치의 값을 약간 낮추면 처벌되지 않습니다.

하나의 대략적인 아이디어는 입력과 수정 된 출력 벡터의 차이에 대해 일반적인 L1 또는 L2 손실을 사용하는 것입니다. 출력에는 옥타브를 처벌하고 차이를 다르게 표시하는 일부 가중치 마스크를 곱할 수 있습니다.

def create_mask(input_column): 
    r = 10 
    d = 5 
    mask = torch.FloatTensor(input_column.size()) 
    _, max_ind = torch.max(input_column, 0) 
    max_ind = int(max_ind[0]) 
    for i in range(mask.size(0)): 
     mask[i] = r*abs(i-max_ind)%12 + d*abs(i-max_ind)/12 
    return mask 

이것은 대략 작성되었지만 준비가되어 있지는 않지만 이론적으로는 작업을 수행해야합니다. 마스크 벡터는 requires_grad=False으로 설정해야합니다. 각 입력에 대해 정확한 상수이기 때문입니다. 따라서 입력에서 최대 값을 사용할 수는 있지만 출력에는 max을 사용하지 마십시오.

도움이 되었기를 바랍니다.