@@ -11,7 +11,10 @@ def activate_formation_block(exported_fields: ExportedFields, ids: np.ndarray, s
11
11
Z_x : np .ndarray = exported_fields .scalar_field_everywhere
12
12
scalar_value_at_sp : np .ndarray = exported_fields .scalar_field_at_surface_points
13
13
14
- sigm = activate_formation_block_from_args (Z_x , ids , scalar_value_at_sp , sigmoid_slope )
14
+ if LEGACY := False :
15
+ sigm = activate_formation_block_from_args (Z_x , ids , scalar_value_at_sp , sigmoid_slope )
16
+ else :
17
+ sigm = activate_formation_block_from_args_hard_sigmoid (Z_x , ids , scalar_value_at_sp , sigmoid_slope )
15
18
16
19
return sigm
17
20
@@ -33,13 +36,40 @@ def activate_formation_block_from_args(Z_x, ids, scalar_value_at_sp, sigmoid_slo
33
36
sigm = bt .t .zeros ((1 , Z_x .shape [0 ]), dtype = BackendTensor .dtype_obj )
34
37
35
38
for i in range (len (ids )):
36
- if LEGACY := True :
37
- sigm += _compute_sigmoid (Z_x , scalar_0_v [i ], scalar_1_v [i ], drift_0_v [i ], drift_1_v [i ], ids [i ], sigmoid_slope )
38
- else :
39
- sigm += HardSigmoid .apply (Z_x , scalar_0_v [i ], scalar_1_v [i ])
39
+ sigm += _compute_sigmoid (Z_x , scalar_0_v [i ], scalar_1_v [i ], drift_0_v [i ], drift_1_v [i ], ids [i ], sigmoid_slope )
40
40
return sigm
41
41
42
42
43
+ def activate_formation_block_from_args_hard_sigmoid (Z_x , ids , scalar_value_at_sp , sigmoid_slope ):
44
+ element_0 = bt .t .array ([0 ], dtype = BackendTensor .dtype_obj )
45
+
46
+ min_Z_x = BackendTensor .t .min (Z_x , axis = 0 ).reshape (- 1 ) # ? Is this as good as it gets?
47
+ max_Z_x = BackendTensor .t .max (Z_x , axis = 0 )[0 ].reshape (- 1 ) # ? Is this as good as it gets?
48
+
49
+ # Add 5%
50
+ min_Z_x = min_Z_x - 0.05 * (max_Z_x - min_Z_x )
51
+ max_Z_x = max_Z_x + 0.05 * (max_Z_x - min_Z_x )
52
+
53
+
54
+ drift_0_v = bt .tfnp .concatenate ([min_Z_x , scalar_value_at_sp ])
55
+ drift_1_v = bt .tfnp .concatenate ([scalar_value_at_sp , max_Z_x ])
56
+
57
+ ids = bt .t .array (ids , dtype = "int32" )
58
+ scalar_0_v = bt .t .copy (ids )
59
+ scalar_0_v [0 ] = 0
60
+ #
61
+ # scalar_1_v = bt.t.copy(ids)
62
+ # scalar_1_v[-1] = 0
63
+
64
+ # * Iterate over surface
65
+ sigm = bt .t .zeros ((1 , Z_x .shape [0 ]), dtype = BackendTensor .dtype_obj )
66
+
67
+ for i in range (len (ids )):
68
+ # if (i == 3):
69
+ sigm += ids [i ] * HardSigmoidModified .apply (Z_x , drift_0_v [i ], drift_1_v [i ])
70
+ return sigm .view (1 , - 1 )
71
+
72
+
43
73
def _compute_sigmoid (Z_x , scale_0 , scale_1 , drift_0 , drift_1 , drift_id , sigmoid_slope ):
44
74
# TODO: Test to remove reshape once multiple values are implemented
45
75
@@ -49,9 +79,9 @@ def _compute_sigmoid(Z_x, scale_0, scale_1, drift_0, drift_1, drift_id, sigmoid_
49
79
50
80
sigmoid_slope_tensor = BackendTensor .t .array (sigmoid_slope , dtype = BackendTensor .dtype_obj )
51
81
52
- active_denominator = (1 + bt .tfnp .exp (- sigmoid_slope_tensor * (Z_x - drift_0 )))
82
+ active_denominator = (1 + bt .tfnp .exp (- sigmoid_slope_tensor * (Z_x - drift_0 )))
53
83
deactive_denominator = (1 + bt .tfnp .exp (sigmoid_slope_tensor * (Z_x - drift_1 )))
54
-
84
+
55
85
active_sig = - scale_0 .reshape ((- 1 , 1 )) / active_denominator
56
86
deactive_sig = - scale_1 .reshape ((- 1 , 1 )) / deactive_denominator
57
87
activation_sig = active_sig + deactive_sig
@@ -71,25 +101,61 @@ def _add_relu():
71
101
72
102
# * This gets the scalar gradient
73
103
import torch
74
- class HardSigmoid (torch .autograd .Function ):
104
+
105
+
106
+ class HardSigmoidModified (torch .autograd .Function ):
75
107
@staticmethod
76
108
def forward (ctx , input , a , b ):
77
109
ctx .save_for_backward (input )
78
110
ctx .bounds = (a , b )
79
- slope = 1 / (b - a )
80
- return torch .clamp (slope * (input - a ) + 0.5 , min = 0 , max = 1 )
111
+ output = torch .zeros_like (input )
112
+ slope_up = 100 / (b - a )
113
+
114
+ # For x in the range [a, b]
115
+ output [(input >= a ) & (input <= b )] += torch .clamp (slope_up * (input [(input >= a ) & (input <= b )] - a ), min = 0 , max = 1 )
116
+
117
+ output [(input >= a ) & (input <= b )] += torch .clamp (- slope_up * (input [(input >= a ) & (input <= b )] - b ), min = 0 , max = 1 )
118
+
119
+ # Clamping the values outside the range [a, c] to zero
120
+ output [input < a ] = 0
121
+ output [input >= b ] = 0
122
+
123
+ return output
124
+
81
125
82
126
@staticmethod
83
127
def backward (ctx , grad_output ):
84
128
input , = ctx .saved_tensors
85
129
a , b = ctx .bounds
130
+ midpoint = (a + b ) / 2
86
131
grad_input = grad_output .clone ()
132
+
133
+ # Gradient is 1/(b-a) for x in [a, midpoint), -1/(b-a) for x in (midpoint, b], and 0 elsewhere
87
134
grad_input [input < a ] = 0
88
135
grad_input [input > b ] = 0
89
- grad_input [(input >= a ) & (input <= b )] = 1 / (b - a )
136
+ grad_input [(input >= a ) & (input < midpoint )] = 1 / (b - a )
137
+ grad_input [(input > midpoint ) & (input <= b )] = - 1 / (b - a )
138
+
90
139
return grad_input , None , None
91
140
92
141
142
+ class HardSigmoid (torch .autograd .Function ):
143
+ @staticmethod
144
+ def forward (ctx , input , a , b , c ):
145
+ ctx .save_for_backward (input )
146
+ ctx .bounds = (a , b )
147
+ slope = 1000 / (b - a )
148
+ return torch .clamp (slope * (input - a ) + 0.5 , min = 0 , max = 1 )
149
+
150
+ @staticmethod
151
+ def backward (ctx , grad_output ):
152
+ input , = ctx .saved_tensors
153
+ a , b = ctx .bounds
154
+ grad_input = grad_output .clone ()
155
+ grad_input [input < a ] = 0
156
+ grad_input [input > b ] = 0
157
+ grad_input [(input >= a ) & (input <= b )] = 1 / (b - a )
158
+ return grad_input , None , None
93
159
94
160
95
161
class CustomSigmoidFunction (torch .autograd .Function ):
0 commit comments