| 470 | |
| 471 | template<OptimizerType optimizer_type> |
| 472 | __host__ __device__ |
| 473 | static void backward(Vector &head, Vector &tail, Vector &relation, |
| 474 | float margin, Float gradient, const Optimizer &optimizer, |
| 475 | float relation_lr_multiplier = 1, Float weight = 1) { |
| 476 | auto update = get_update_function<Float, optimizer_type>(); |
| 477 | FOR(i, dim / 2) { |
| 478 | Float phase = relation[i]; |
| 479 | Float r_re = cos(phase); |
| 480 | Float r_im = sin(phase); |
| 481 | Float h_re = head[i * 2]; |
| 482 | Float h_im = head[i * 2 + 1]; |
| 483 | Float t_re = tail[i * 2]; |
| 484 | Float t_im = tail[i * 2 + 1]; |
| 485 | Float distance_re = h_re * r_re - h_im * r_im - t_re; |
| 486 | Float distance_im = h_re * r_im + h_im * r_re - t_im; |
| 487 | Float grad = gradient / (sqrt(distance_re * distance_re + distance_im * distance_im) + kEpsilon); |
| 488 | // head |
| 489 | Float head_re_grad = -grad * (distance_re * r_re + distance_im * r_im); |
| 490 | Float head_im_grad = -grad * (-distance_re * r_im + distance_im * r_re); |
| 491 | head[i * 2] -= (optimizer.*update)(h_re, head_re_grad, weight); |
| 492 | head[i * 2 + 1] -= (optimizer.*update)(h_im, head_im_grad, weight); |
| 493 | // tail |
| 494 | tail[i * 2] -= (optimizer.*update)(t_re, grad * distance_re, weight); |
| 495 | tail[i * 2 + 1] -= (optimizer.*update)(t_im, grad * distance_im, weight); |
| 496 | // relation |
| 497 | Float relation_grad = |
| 498 | -grad * (distance_re * (h_re * -r_im + h_im * -r_re) + distance_im * (h_re * r_re + h_im * -r_im)); |
| 499 | relation[i] -= relation_lr_multiplier * (optimizer.*update)(phase, relation_grad, weight); |
| 500 | } |
| 501 | } |
| 502 | |
| 503 | template<OptimizerType optimizer_type> |
| 504 | __host__ __device__ |
nothing calls this directly
no outgoing calls
no test coverage detected