-
Notifications
You must be signed in to change notification settings - Fork 0
/
learning.py
112 lines (102 loc) · 4.2 KB
/
learning.py
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
"""TODO."""
import numpy as np
import math
import random
from inference import draw_sample, eval_factor
def learnthread(step, regularization, reg_param,
weight,
variable, factor, fmap,
vmap, factor_index, Z, fids, var_value, var_value_evid,
weight_value, learn_non_evidence):
"""TODO."""
# Identify start and end variable
nvar = variable.shape[0]
start = 0
end = nvar
for var_samp in range(start, end):
sample_and_sgd(var_samp, step, regularization, reg_param,
weight, variable,
factor, fmap, vmap,
factor_index, Z[0], fids[0], var_value,
var_value_evid, weight_value, learn_non_evidence)
def get_factor_id_range(variable, vmap, var_samp, val):
"""TODO."""
varval_off = 0
vtf = vmap[variable[var_samp]["vtf_offset"] + varval_off]
start = vtf["factor_index_offset"]
end = start + vtf["factor_index_length"]
return (start, end)
def sample_and_sgd(var_samp, step, regularization, reg_param,
weight, variable, factor, fmap,
vmap, factor_index, Z, fids, var_value, var_value_evid,
weight_value, learn_non_evidence):
"""TODO."""
# If learn_non_evidence sample twice.
# The method corresponds to expectation-conjugate descent.
if variable[var_samp]["isEvidence"] != 1:
evidence = draw_sample(var_samp,
weight, variable, factor,
fmap, vmap, factor_index, Z,
var_value_evid, weight_value)
# If evidence then store the initial value in a tmp variable
# then sample and compute the gradient.
else:
evidence = variable[var_samp]["initialValue"]
var_value_evid[0][var_samp] = evidence
# Sample the variable
proposal = draw_sample(var_samp, weight,
variable, factor, fmap, vmap,
factor_index, Z, var_value, weight_value)
var_value[0][var_samp] = proposal
if not learn_non_evidence and variable[var_samp]["isEvidence"] != 1:
return
# Compute the gradient and update the weights
# Iterate over corresponding factors
range_fids = get_factor_id_range(variable, vmap, var_samp, evidence)
# TODO: is it possible to avoid copying around fids
if evidence != proposal:
range_prop = get_factor_id_range(variable, vmap, var_samp, proposal)
s1 = range_fids[1] - range_fids[0]
s2 = range_prop[1] - range_prop[0]
s = s1 + s2
fids[:s1] = factor_index[range_fids[0]:range_fids[1]]
fids[s1:s] = factor_index[range_prop[0]:range_prop[1]]
fids[:s].sort()
else:
s = range_fids[1] - range_fids[0]
fids[:s] = factor_index[range_fids[0]:range_fids[1]]
# go over all factor ids, ignoring dupes
last_fid = -1 # numba 0.28 would complain if this were None
for factor_id in fids[:s]:
if factor_id == last_fid:
continue
last_fid = factor_id
weight_id = factor[factor_id]["weightId"]
if weight[weight_id]["isFixed"]:
continue
# Compute Gradient
p0 = eval_factor(factor_id, var_samp,
evidence,
variable, factor, fmap,
var_value_evid) * factor[factor_id]["featureValue"]
p1 = eval_factor(factor_id, var_samp,
proposal,
variable, factor, fmap,
var_value) * factor[factor_id]["featureValue"]
gradient = p1 - p0
# Update weight
w = weight_value[0][weight_id]
if regularization == 2:
w *= (1.0 / (1.0 + reg_param * step))
w -= step * gradient
elif regularization == 1:
# Truncated Gradient
# "Sparse Online Learning via Truncated Gradient"
# Langford et al. 2009
l1delta = reg_param * step
w -= step * gradient
w = max(0, w - l1delta) if w > 0 \
else min(0, w + l1delta)
else:
w -= step * gradient
weight_value[0][weight_id] = w