| 444 | */ |
| 445 | template<class _Vector> |
| 446 | class RotatE { |
| 447 | public: |
| 448 | static_assert(_Vector::dim % 2 == 0, "Model `RotatE` can only be instantiated with even-dimensional vectors"); |
| 449 | static const size_t dim = _Vector::dim; |
| 450 | typedef _Vector Vector; |
| 451 | typedef typename _Vector::Float Float; |
| 452 | |
| 453 | __host__ __device__ |
| 454 | static void forward(const Vector &head, const Vector &tail, const Vector &relation, Float &output, float margin) { |
| 455 | output = 0; |
| 456 | FOR(i, dim / 2) { |
| 457 | Float h_re = head[i * 2]; |
| 458 | Float h_im = head[i * 2 + 1]; |
| 459 | Float t_re = tail[i * 2]; |
| 460 | Float t_im = tail[i * 2 + 1]; |
| 461 | Float phase = relation[i]; |
| 462 | Float r_re = cos(phase); |
| 463 | Float r_im = sin(phase); |
| 464 | Float distance_re = h_re * r_re - h_im * r_im - t_re; |
| 465 | Float distance_im = h_re * r_im + h_im * r_re - t_im; |
| 466 | output += sqrt(distance_re * distance_re + distance_im * distance_im); |
| 467 | } |
| 468 | output = margin - SUM(output); |
| 469 | } |
| 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> |
nothing calls this directly
no outgoing calls
no test coverage detected