forked from IQVIA-ML/TreeParzen.jl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHP.jl
396 lines (307 loc) · 10.8 KB
/
HP.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
module HP
using DocStringExtensions
import ..Delayed
export Prob
"""
$(TYPEDEF)
$(TYPEDFIELDS)
State the weighted probability of an option, for use with PChoice.
"""
struct Prob
probability::Float64
option
end
struct PChoice <: Delayed.AbstractSwitch
choice::Delayed.Param
options::Vector
@doc """
$(TYPEDSIGNATURES)
Choose from a list of options with weighted probabilities
# Arguments
- `label` : Label
- `probability_options` : Array of Prob objects
Example:
```julia
HP.PChoice(:a, [
Prob(0.1, 0),
Prob(0.2, 1),
Prob(0.7, 2),
])
```
Note that the Prob probability weights must sum to 1.
"""
function PChoice(label::Symbol, probability_options::Vector{Prob})
if isempty(probability_options)
throw(ArgumentError("$(label): you must give at least one choice"))
end
probabilities = [o.probability for o in probability_options]
if sum(probabilities) != 1
throw(ArgumentError("Prob probability weights must sum to 1"))
end
options = [o.option for o in probability_options]
return new(Delayed.Param(label, Delayed.CategoricalIndex(probabilities)), options)
end
end
struct Choice <: Delayed.AbstractSwitch
choice::Delayed.Param
options::Vector
@doc """
$(TYPEDSIGNATURES)
Randomly choose which option will be extracted, and also supply the list of options.
The elements of options can themselves be [nested] stochastic expressions. In this case, the
stochastic choices that only appear in some of the options become conditional parameters.
Example:
```julia
Dict(
:example => HP.Choice(:example, [1.0, 0.9, 0.8, 0.7]),
)
```
Example of conditional paramaters:
```julia
Dict(
:example => HP.Choice(:example, [
(:case1, HP.Uniform(:param1, 0.0, 1.0)),
(:case2, HP.Uniform(:param2, -10.0, 10.0)),
]),
)
```
':param1' and ':param2' are examples of conditional parameters. Each of ':param1' and
':param2' only features in the returned sample for a particular value of ':example'. If
':example' is 0, then ':param1' is used but not ':param2'. If ':example' is 1, then
':param2' is used but not ':param1'.
Example with nested arrays of different lengths:
```julia
Dict(
:example => HP.Choice(:example, [
[HP.Normal(:d0_c0, 0.0, 5.0)],
[HP.Normal(:d1_c0, 0.0, 5.0), HP.Normal(:d1_c1, 0.0, 5.0)],
[
HP.Normal(:d2_c0, 0.0, 5.0), HP.Normal(:d2_c1, 0.0, 5.0),
HP.Normal(:d2_c2, 0.0, 5.0),
],
]),
)
```
Note that all labels (the symbol given as the first parameter to all the HP.* functions)
must be unique. These labels identify the parts of the space that the optimiser learns from
over iterations.
"""
function Choice(label::Symbol, options::Vector)
if isempty(options)
throw(ArgumentError("$(label): you must give at least one choice"))
end
return new(Delayed.Param(label, Delayed.RandIndex(length(options))), options)
end
end
struct Uniform <: Delayed.AbstractParam
label::Symbol
obj::Delayed.Uniform
@doc """
$(TYPEDSIGNATURES)
Returns a value with uniform probability from between `low` and `high`.
When optimising, this variable is constrained to a two-sided interval.
```julia
Dict(
:example => HP.Uniform(:example, 0.0, 1.0),
)
```
where `label` is the parameter and the returned value is uniformly distributed between
`low` at 0.0 and `high` at 1.0
"""
function Uniform(label::Symbol, low::Delayed.NestedFloat, high::Delayed.NestedFloat)
return new(label, Delayed.Uniform(low, high))
end
end
struct QuantUniform <: Delayed.AbstractParam
label::Symbol
obj::Delayed.QuantUniform
@doc """
$(TYPEDSIGNATURES)
Returns a value uniformly between low and high, with a quantisation.
When optimising, this variable is constrained to a two-sided interval.
```julia
Dict(
:example => HP.QuantUniform(:example, 0.0, 10.0, 2.0),
)
```
where `label` is the parameter and the returned value is uniformly distributed between
`low` at 0.0 and `high` at 10.0, with the `q`uantisation set at 2.0.
Valid sampled values would be 0.0, 2.0, 4.0, 6.0, 8.0 and 10.0.
"""
function QuantUniform(
label::Symbol, low::Delayed.NestedFloat, high::Delayed.NestedFloat,
q::Delayed.NestedFloat
)
return new(label, Delayed.QuantUniform(low, high, q))
end
end
struct Normal <: Delayed.AbstractParam
label::Symbol
obj::Delayed.Normal
@doc """
$(TYPEDSIGNATURES)
Returns a real value that's normally-distributed with mean mu and standard deviation sigma.
When optimizing, this is an unconstrained variable.
```julia
Dict(
:example => HP.Normal(:example, 4.0, 5.0),
)
```
"""
function Normal(label::Symbol, mu::Delayed.NestedFloat, sigma::Delayed.NestedFloat)
return new(label, Delayed.Normal(mu, sigma))
end
end
struct QuantNormal <: Delayed.AbstractParam
label::Symbol
obj::Delayed.QuantNormal
@doc """
$(TYPEDSIGNATURES)
Returns a real value that's normally-distributed with mean mu and standard deviation sigma, with a quantisation.
When optimizing, this is an unconstrained variable.
```julia
Dict(
:example => HP.QuantNormal(:example, 2., 0.5, 1.0),
)
```
In this example, the values are sampled normally first, and then `q`uantised in rounds of 1.0, so one
only observes 1.0, 2.0, 3.0, etc, centered around 2.0.
N.B. that due to rounding, the observed values will not follow exactly normal distribution, particularly
if sigma is much smaller than quantisation.
"""
function QuantNormal(
label::Symbol, mu::Delayed.NestedFloat, sigma::Delayed.NestedFloat,
q::Delayed.NestedFloat
)
return new(label, Delayed.QuantNormal(mu, sigma, q))
end
end
struct LogNormal <: Delayed.AbstractParam
label::Symbol
obj::Delayed.LogNormal
@doc """
$(TYPEDSIGNATURES)
Returns a value drawn according to exp(normal(mu, sigma)) so that the logarithm of the
sampled value is normally distributed. When optimising, this variable is constrained to be
positive.
```julia
Dict(
:example => HP.LogNormal(:example, log(3.0), 0.5),
)
```
In this example, the log normal distribution will be centred around 3. The distribution is
not truncated.
"""
function LogNormal(label::Symbol, mu::Delayed.NestedFloat, sigma::Delayed.NestedFloat)
return new(label, Delayed.LogNormal(mu, sigma))
end
end
struct LogQuantNormal <: Delayed.AbstractParam
label::Symbol
obj::Delayed.LogQuantNormal
@doc """
$(TYPEDSIGNATURES)
Returns a value drawn according to exp(normal(mu, sigma)), with a quantisation, so that the
logarithm of the sampled value is normally distributed. When optimising, this variable is
constrained to be positive.
```julia
Dict(
:example => HP.LogQuantNormal(:example, log(1e-3), 0.5*log(10), log(sqrt(10))),
)
```
In this example, the log normal distribution will be centred around 1e-3, with stddev of sqrt(10) (in exp).
The distribution is not truncated. The distinct values would therefore be in every power of `sqrt(10)`.
"""
function LogQuantNormal(
label::Symbol, mu::Delayed.NestedFloat, sigma::Delayed.NestedFloat,
q::Delayed.NestedFloat
)
return new(label, Delayed.LogQuantNormal(mu, sigma, q))
end
end
struct QuantLogNormal <: Delayed.AbstractParam
label::Symbol
obj::Delayed.QuantLogNormal
@doc """
$(TYPEDSIGNATURES)
Returns a value drawn according to exp(normal(mu, sigma)), with a quantisation, so that the
logarithm of the sampled value is normally distributed. When optimising, this variable is
constrained to be positive.
```julia
Dict(
:example => HP.QuantLogNormal(:example, log(3.0), 0.5, 2.0),
)
```
In this example, the log normal distribution will be centred around 3. The distribution is
not truncated. The values with be quantised to multiples of 2, i.e. 2.0, 4.0, 6.0, etc.
"""
function QuantLogNormal(
label::Symbol, mu::Delayed.NestedFloat, sigma::Delayed.NestedFloat,
q::Delayed.NestedFloat
)
return new(label, Delayed.QuantLogNormal(mu, sigma, q))
end
end
struct LogUniform <: Delayed.AbstractParam
label::Symbol
obj::Delayed.LogUniform
@doc """
$(TYPEDSIGNATURES)
Returns a value drawn according to exp(uniform(low, high)) such that the logarithm
of the return value is uniformly distributed.
When optimizing, this variable is constrained to the interval [exp(low), exp(high)].
```julia
Dict(
:example => HP.LogUniform(:example, log(3.0), 1.0),
)
```
"""
function LogUniform(label::Symbol, low::Delayed.NestedFloat, high::Delayed.NestedFloat)
return new(label, Delayed.LogUniform(low, high))
end
end
struct LogQuantUniform <: Delayed.AbstractParam
label::Symbol
obj::Delayed.LogQuantUniform
@doc """
$(TYPEDSIGNATURES)
Returns a value drawn according to exp(uniform(low, high)), quantised in log-space, such that
the logarithm of the return value is uniformly distributed. The value is constrained to be positive.
Suitable for searching logarithmically through a space while keeping the number of candidates
bounded, e.g. searching learning rate through 1e-6 to 1e-1
```julia
Dict(
:example => HP.LogQuantUniform(:example, log(1e-6), log(1e-1), log(10)),
)
```
"""
function LogQuantUniform(
label::Symbol, low::Delayed.NestedFloat, high::Delayed.NestedFloat,
q::Delayed.NestedFloat
)
return new(label, Delayed.LogQuantUniform(low, high, q))
end
end
struct QuantLogUniform <: Delayed.AbstractParam
label::Symbol
obj::Delayed.QuantLogUniform
@doc """
$(TYPEDSIGNATURES)
Returns a value drawn according to exp(uniform(low, high)), with a quantisation q, such that
the logarithm of the return value is uniformly distributed.
Suitable for a discrete variable with respect to which the objective is "smooth" and gets
smoother with the size of the value, but which should be bounded both above and below.
```julia
Dict(
:example => HP.QuantLogUniform(:example, log(3.0), log(10.0), 2.0),
)
```
"""
function QuantLogUniform(
label::Symbol, low::Delayed.NestedFloat, high::Delayed.NestedFloat,
q::Delayed.NestedFloat
)
return new(label, Delayed.QuantLogUniform(low, high, q))
end
end
end # module HP