Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
C
Climax
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Deploy
Releases
Package registry
Container Registry
Model registry
Operate
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
earth_observation_public
Climax
Commits
048d866d
Commit
048d866d
authored
3 years ago
by
Frisinghelli Daniel
Browse files
Options
Downloads
Patches
Plain Diff
Stable implementation of Bernoulli-Gamma and Bernoulli-Weibull loss.
parent
d4deb150
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
climax/core/loss.py
+47
-100
47 additions, 100 deletions
climax/core/loss.py
with
47 additions
and
100 deletions
climax/core/loss.py
+
47
−
100
View file @
048d866d
...
...
@@ -48,8 +48,7 @@ class L1Loss(NaNLoss):
return
F
.
l1_loss
(
y_pred
[
mask
],
y_true
[
mask
],
reduction
=
self
.
reduction
)
class
BernoulliGammaLoss
(
NaNLoss
):
class
BernoulliLoss
(
NaNLoss
):
def
__init__
(
self
,
size_average
=
None
,
reduce
=
None
,
reduction
=
'
mean
'
,
min_amount
=
0
):
super
().
__init__
(
size_average
,
reduce
,
reduction
)
...
...
@@ -57,6 +56,13 @@ class BernoulliGammaLoss(NaNLoss):
# minimum amount of precipitation to be classified as precipitation
self
.
min_amount
=
min_amount
class
BernoulliGammaLoss
(
BernoulliLoss
):
def
__init__
(
self
,
size_average
=
None
,
reduce
=
None
,
reduction
=
'
mean
'
,
min_amount
=
0
):
super
().
__init__
(
size_average
,
reduce
,
reduction
,
min_amount
)
def
forward
(
self
,
y_pred
,
y_true
):
# convert to float32
...
...
@@ -67,34 +73,34 @@ class BernoulliGammaLoss(NaNLoss):
mask
=
~
torch
.
isnan
(
y_true
)
y_true
=
y_true
[
mask
]
# mask values less than 0
y_true
[
y_true
<
0
]
=
0
# calculate true probability of precipitation:
# 1 if y_true > min_amount else 0
p_true
=
(
y_true
>
self
.
min_amount
).
type
(
torch
.
float32
)
# estimates of precipitation probability and gamma shape and scale
# parameters: ensure numerical stability
# mask for values < min_amount
mask_p
=
y_true
<
self
.
min_amount
y_gamm
=
y_true
[
~
mask_p
]
# clip probabilities to (0, 1)
p_pred
=
torch
.
sigmoid
(
y_pred
[:,
0
,
...].
squeeze
()[
mask
])
# clip shape and scale to (0, +infinity)
gshape
=
torch
.
exp
(
y_pred
[:,
1
,
...].
squeeze
()[
mask
])
gscale
=
torch
.
exp
(
y_pred
[:,
2
,
...].
squeeze
()[
mask
])
gshape
=
torch
.
exp
(
y_pred
[:,
1
,
...].
squeeze
()[
mask
]
[
~
mask_p
]
)
gscale
=
torch
.
exp
(
y_pred
[:,
2
,
...].
squeeze
()[
mask
]
[
~
mask_p
]
)
# negative log-likelihood function of Bernoulli-Gamma distribution
loss
=
torch
.
zeros_like
(
y_true
)
# Bernoulli contribution
loss
=
-
(
1
-
p_true
)
*
torch
.
log
(
1
-
p_pred
+
self
.
epsilon
)
loss
_bern
=
torch
.
log
(
1
-
p_pred
[
mask_p
]
+
self
.
epsilon
)
# Gamma contribution
loss
-=
p_true
*
(
torch
.
log
(
p_pred
+
self
.
epsilon
)
+
(
gshape
-
1
)
*
torch
.
log
(
y_true
+
self
.
epsilon
)
-
y_true
/
(
gscale
+
self
.
epsilon
)
-
gshape
*
torch
.
log
(
gscale
+
self
.
epsilon
)
-
torch
.
lgamma
(
gshape
+
self
.
epsilon
))
loss_gamm
=
(
torch
.
log
(
p_pred
[
~
mask_p
]
+
self
.
epsilon
)
+
(
gshape
-
1
)
*
torch
.
log
(
y_gamm
+
self
.
epsilon
)
-
y_gamm
/
(
gscale
+
self
.
epsilon
)
-
gshape
*
torch
.
log
(
gscale
+
self
.
epsilon
)
-
torch
.
lgamma
(
gshape
+
self
.
epsilon
)
)
# fill loss array
loss
[
torch
.
where
(
mask_p
)]
=
-
loss_bern
loss
[
torch
.
where
(
~
mask_p
)]
=
-
loss_gamm
return
self
.
reduce
(
loss
)
...
...
@@ -104,14 +110,11 @@ class BernoulliGammaLoss(NaNLoss):
return
p
*
np
.
exp
(
shape
)
*
np
.
exp
(
scale
)
class
Bernoulli
GenParetoLoss
(
NaN
Loss
):
class
Bernoulli
WeibullLoss
(
Bernoulli
Loss
):
def
__init__
(
self
,
size_average
=
None
,
reduce
=
None
,
reduction
=
'
mean
'
,
min_amount
=
0
):
super
().
__init__
(
size_average
,
reduce
,
reduction
)
# minimum amount of precipitation to be classified as precipitation
self
.
min_amount
=
min_amount
super
().
__init__
(
size_average
,
reduce
,
reduction
,
min_amount
)
def
forward
(
self
,
y_pred
,
y_true
):
...
...
@@ -123,95 +126,39 @@ class BernoulliGenParetoLoss(NaNLoss):
mask
=
~
torch
.
isnan
(
y_true
)
y_true
=
y_true
[
mask
]
# mask values less than 0
y_true
[
y_true
<
0
]
=
0
# calculate true probability of precipitation:
# 1 if y_true > min_amount else 0
p_true
=
(
y_true
>
self
.
min_amount
).
type
(
torch
.
float32
)
# estimates of precipitation probability and gamma shape and scale
# parameters: ensure numerical stability
# clip probabilities to (0, 1)
p_pred
=
torch
.
sigmoid
(
y_pred
[:,
0
,
...].
squeeze
()[
mask
])
# clip shape and scale to (0, +infinity)
gshape
=
torch
.
exp
(
y_pred
[:,
1
,
...].
squeeze
()[
mask
])
gscale
=
torch
.
exp
(
y_pred
[:,
2
,
...].
squeeze
()[
mask
])
# negative log-likelihood function of Bernoulli-GenPareto distribution
# Bernoulli contribution
loss
=
-
(
1
-
p_true
)
*
torch
.
log
(
1
-
p_pred
+
self
.
epsilon
)
# GenPareto contribution
loss
-=
p_true
*
(
torch
.
log
(
p_pred
+
self
.
epsilon
)
+
torch
.
log
(
1
-
(
1
+
(
gshape
*
y_true
/
gscale
))
**
(
-
1
/
gshape
)
+
self
.
epsilon
))
return
self
.
reduce
(
loss
)
class
BernoulliWeibullLoss
(
NaNLoss
):
def
__init__
(
self
,
size_average
=
None
,
reduce
=
None
,
reduction
=
'
mean
'
,
min_amount
=
0
):
super
().
__init__
(
size_average
,
reduce
,
reduction
)
# minimum amount of precipitation to be classified as precipitation
self
.
min_amount
=
min_amount
def
forward
(
self
,
y_pred
,
y_true
):
# convert to float32
y_pred
=
y_pred
.
type
(
torch
.
float64
)
y_true
=
y_true
.
type
(
torch
.
float64
).
squeeze
()
# missing values
mask
=
~
torch
.
isnan
(
y_true
)
y_true
=
y_true
[
mask
]
# mask values less than 0
y_true
[
y_true
<
0
]
=
0
# calculate true probability of precipitation:
# 1 if y_true > min_amount else 0
p_true
=
(
y_true
>
self
.
min_amount
).
type
(
torch
.
float32
)
# estimates of precipitation probability and gamma shape and scale
# parameters: ensure numerical stability
# mask for values < min_amount
mask_p
=
y_true
<
self
.
min_amount
y_weib
=
y_true
[
~
mask_p
]
# clip probabilities to (0, 1)
p_pred
=
torch
.
sigmoid
(
y_pred
[:,
0
,
...].
squeeze
()[
mask
])
# clip scale to (0, +infinity)
scale
=
torch
.
exp
(
y_pred
[:,
2
,
...].
squeeze
()[
mask
])
scale
=
torch
.
exp
(
y_pred
[:,
2
,
...].
squeeze
()[
mask
]
[
~
mask_p
]
)
# clip shape to (0, 1)
# NOTE: in general shape in (0, +infinity),
but for precipitation the
#
shape parameter of the Weibull distribution < 1
# clip shape to (0, 1
0
)
# NOTE: in general shape in (0, +infinity),
clipping is required for
#
numerical stability
shape
=
torch
.
clamp
(
torch
.
exp
(
y_pred
[:,
1
,
...].
squeeze
()[
mask
]),
max
=
1
)
torch
.
exp
(
y_pred
[:,
1
,
...].
squeeze
()[
mask
]
[
~
mask_p
]
),
max
=
1
0
)
# negative log-likelihood function of Bernoulli-Weibull distribution
loss
=
torch
.
zeros_like
(
y_true
)
# Bernoulli contribution
loss
=
-
(
1
-
p_true
)
*
torch
.
log
(
1
-
p_pred
+
self
.
epsilon
)
# replace values < min_amount: ensures numerical stability in backprop
y_true
[
y_true
<=
self
.
min_amount
]
=
1
loss_bern
=
torch
.
log
(
1
-
p_pred
[
mask_p
]
+
self
.
epsilon
)
# Weibull contribution
loss
-=
p_true
*
(
torch
.
log
(
p_pred
+
self
.
epsilon
)
+
torch
.
log
(
shape
+
self
.
epsilon
)
-
shape
*
torch
.
log
(
scale
+
self
.
epsilon
)
+
(
shape
-
1
)
*
torch
.
log
(
y_true
+
self
.
epsilon
)
-
torch
.
pow
(
y_true
/
(
scale
+
self
.
epsilon
),
shape
)
)
# clip loss to finite values to ensure numerical stability
# loss = torch.clamp(loss, max=100)
loss_weib
=
(
torch
.
log
(
p_pred
[
~
mask_p
]
+
self
.
epsilon
)
+
torch
.
log
(
shape
+
self
.
epsilon
)
-
shape
*
torch
.
log
(
scale
+
self
.
epsilon
)
+
(
shape
-
1
)
*
torch
.
log
(
y_weib
+
self
.
epsilon
)
-
torch
.
pow
(
y_weib
/
(
scale
+
self
.
epsilon
),
shape
)
)
# fill loss array
loss
[
torch
.
where
(
mask_p
)]
=
-
loss_bern
loss
[
torch
.
where
(
~
mask_p
)]
=
-
loss_weib
return
self
.
reduce
(
loss
)
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment