|
1 | 1 | {{py:
|
2 | 2 |
|
3 | 3 | """
|
4 |
| -Template file for easily generate loops over samples using Tempita |
| 4 | +Template file to easily generate loops over samples using Tempita |
5 | 5 | (https://github.com/cython/cython/blob/master/Cython/Tempita/_tempita.py).
|
6 | 6 |
|
7 | 7 | Generated file: _loss.pyx
|
@@ -117,6 +117,28 @@ doc_HalfTweedieLoss = (
|
117 | 117 | """
|
118 | 118 | )
|
119 | 119 |
|
| 120 | +doc_HalfTweedieLossIdentity = ( |
| 121 | + """Half Tweedie deviance loss with identity link. |
| 122 | + |
| 123 | + Domain: |
| 124 | + y_true in real numbers if p <= 0 |
| 125 | + y_true in non-negative real numbers if 0 < p < 2 |
| 126 | + y_true in positive real numbers if p >= 2 |
| 127 | + y_pred and power in positive real numbers, y_pred may be negative for p=0. |
| 128 | + |
| 129 | + Link: |
| 130 | + y_pred = raw_prediction |
| 131 | + |
| 132 | + Half Tweedie deviance with identity link and p=power is |
| 133 | + max(y_true, 0)**(2-p) / (1-p) / (2-p) |
| 134 | + - y_true * y_pred**(1-p) / (1-p) |
| 135 | + + y_pred**(2-p) / (2-p) |
| 136 | + |
| 137 | + Notes: |
| 138 | + - Here, we do not drop constant terms in contrast to the version with log-link. |
| 139 | + """ |
| 140 | +) |
| 141 | + |
120 | 142 | doc_HalfBinomialLoss = (
|
121 | 143 | """Half Binomial deviance loss with logit link.
|
122 | 144 |
|
@@ -151,6 +173,9 @@ class_list = [
|
151 | 173 | ("CyHalfTweedieLoss", doc_HalfTweedieLoss, "power",
|
152 | 174 | "closs_half_tweedie", "closs_grad_half_tweedie",
|
153 | 175 | "cgradient_half_tweedie", "cgrad_hess_half_tweedie"),
|
| 176 | + ("CyHalfTweedieLossIdentity", doc_HalfTweedieLossIdentity, "power", |
| 177 | + "closs_half_tweedie_identity", "closs_grad_half_tweedie_identity", |
| 178 | + "cgradient_half_tweedie_identity", "cgrad_hess_half_tweedie_identity"), |
154 | 179 | ("CyHalfBinomialLoss", doc_HalfBinomialLoss, None,
|
155 | 180 | "closs_half_binomial", "closs_grad_half_binomial",
|
156 | 181 | "cgradient_half_binomial", "cgrad_hess_half_binomial"),
|
@@ -194,7 +219,7 @@ from cython.parallel import parallel, prange
|
194 | 219 | import numpy as np
|
195 | 220 | cimport numpy as np
|
196 | 221 |
|
197 |
| -from libc.math cimport exp, fabs, log, log1p |
| 222 | +from libc.math cimport exp, fabs, log, log1p, pow |
198 | 223 | from libc.stdlib cimport malloc, free
|
199 | 224 |
|
200 | 225 | np.import_array()
|
@@ -420,7 +445,7 @@ cdef inline double_pair cgrad_hess_half_gamma(
|
420 | 445 |
|
421 | 446 |
|
422 | 447 | # Half Tweedie Deviance with Log-Link, dropping constant terms
|
423 |
| -# Note that by dropping constants this is no longer smooth in parameter power. |
| 448 | +# Note that by dropping constants this is no longer continuous in parameter power. |
424 | 449 | cdef inline double closs_half_tweedie(
|
425 | 450 | double y_true,
|
426 | 451 | double raw_prediction,
|
@@ -501,6 +526,102 @@ cdef inline double_pair cgrad_hess_half_tweedie(
|
501 | 526 | return gh
|
502 | 527 |
|
503 | 528 |
|
| 529 | +# Half Tweedie Deviance with identity link, without dropping constant terms! |
| 530 | +# Therefore, best loss value is zero. |
| 531 | +cdef inline double closs_half_tweedie_identity( |
| 532 | + double y_true, |
| 533 | + double raw_prediction, |
| 534 | + double power |
| 535 | +) nogil: |
| 536 | + cdef double tmp |
| 537 | + if power == 0.: |
| 538 | + return closs_half_squared_error(y_true, raw_prediction) |
| 539 | + elif power == 1.: |
| 540 | + if y_true == 0: |
| 541 | + return raw_prediction |
| 542 | + else: |
| 543 | + return y_true * log(y_true/raw_prediction) + raw_prediction - y_true |
| 544 | + elif power == 2.: |
| 545 | + return log(raw_prediction/y_true) + y_true/raw_prediction - 1. |
| 546 | + else: |
| 547 | + tmp = pow(raw_prediction, 1. - power) |
| 548 | + tmp = raw_prediction * tmp / (2. - power) - y_true * tmp / (1. - power) |
| 549 | + if y_true > 0: |
| 550 | + tmp += pow(y_true, 2. - power) / ((1. - power) * (2. - power)) |
| 551 | + return tmp |
| 552 | + |
| 553 | + |
| 554 | +cdef inline double cgradient_half_tweedie_identity( |
| 555 | + double y_true, |
| 556 | + double raw_prediction, |
| 557 | + double power |
| 558 | +) nogil: |
| 559 | + if power == 0.: |
| 560 | + return raw_prediction - y_true |
| 561 | + elif power == 1.: |
| 562 | + return 1. - y_true / raw_prediction |
| 563 | + elif power == 2.: |
| 564 | + return (raw_prediction - y_true) / (raw_prediction * raw_prediction) |
| 565 | + else: |
| 566 | + return pow(raw_prediction, -power) * (raw_prediction - y_true) |
| 567 | + |
| 568 | + |
| 569 | +cdef inline double_pair closs_grad_half_tweedie_identity( |
| 570 | + double y_true, |
| 571 | + double raw_prediction, |
| 572 | + double power |
| 573 | +) nogil: |
| 574 | + cdef double_pair lg |
| 575 | + cdef double tmp |
| 576 | + if power == 0.: |
| 577 | + lg.val2 = raw_prediction - y_true # gradient |
| 578 | + lg.val1 = 0.5 * lg.val2 * lg.val2 # loss |
| 579 | + elif power == 1.: |
| 580 | + if y_true == 0: |
| 581 | + lg.val1 = raw_prediction |
| 582 | + else: |
| 583 | + lg.val1 = (y_true * log(y_true/raw_prediction) # loss |
| 584 | + + raw_prediction - y_true) |
| 585 | + lg.val2 = 1. - y_true / raw_prediction # gradient |
| 586 | + elif power == 2.: |
| 587 | + lg.val1 = log(raw_prediction/y_true) + y_true/raw_prediction - 1. # loss |
| 588 | + tmp = raw_prediction * raw_prediction |
| 589 | + lg.val2 = (raw_prediction - y_true) / tmp # gradient |
| 590 | + else: |
| 591 | + tmp = pow(raw_prediction, 1. - power) |
| 592 | + lg.val1 = (raw_prediction * tmp / (2. - power) # loss |
| 593 | + - y_true * tmp / (1. - power)) |
| 594 | + if y_true > 0: |
| 595 | + lg.val1 += (pow(y_true, 2. - power) |
| 596 | + / ((1. - power) * (2. - power))) |
| 597 | + lg.val2 = tmp * (1. - y_true / raw_prediction) # gradient |
| 598 | + return lg |
| 599 | + |
| 600 | + |
| 601 | +cdef inline double_pair cgrad_hess_half_tweedie_identity( |
| 602 | + double y_true, |
| 603 | + double raw_prediction, |
| 604 | + double power |
| 605 | +) nogil: |
| 606 | + cdef double_pair gh |
| 607 | + cdef double tmp |
| 608 | + if power == 0.: |
| 609 | + gh.val1 = raw_prediction - y_true # gradient |
| 610 | + gh.val2 = 1. # hessian |
| 611 | + elif power == 1.: |
| 612 | + gh.val1 = 1. - y_true / raw_prediction # gradient |
| 613 | + gh.val2 = y_true / (raw_prediction * raw_prediction) # hessian |
| 614 | + elif power == 2.: |
| 615 | + tmp = raw_prediction * raw_prediction |
| 616 | + gh.val1 = (raw_prediction - y_true) / tmp # gradient |
| 617 | + gh.val2 = (-1. + 2. * y_true / raw_prediction) / tmp # hessian |
| 618 | + else: |
| 619 | + tmp = pow(raw_prediction, -power) |
| 620 | + gh.val1 = tmp * (raw_prediction - y_true) # gradient |
| 621 | + gh.val2 = tmp * ((1. - power) + power * y_true / raw_prediction) # hessian |
| 622 | + return gh |
| 623 | + |
| 624 | + |
504 | 625 | # Half Binomial deviance with logit-link, aka log-loss or binary cross entropy
|
505 | 626 | cdef inline double closs_half_binomial(
|
506 | 627 | double y_true,
|
|
0 commit comments