Skip to content

Commit 2a95c0a

Browse files
committed
holdout likelihood added
1 parent 718e3f0 commit 2a95c0a

File tree

2 files changed

+194
-0
lines changed

2 files changed

+194
-0
lines changed

ptm/link_prediction.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import cPickle
2+
#cd Desktop/git/author_citation/cora
3+
4+
doc_cnt = cPickle.load(open('doc_cnt.pkl'))
5+
doc_ids = cPickle.load(open('doc_ids.pkl'))
6+
doc_links = cPickle.load(open('doc_links_sym.pkl'))
7+
bow = cPickle.load(open('bow.pkl'))
8+
9+
'''
10+
test_docs = random.choice(range(len(doc_cnt)), size = 100, replace = False)
11+
test_list = list(test_docs)
12+
for v in test_docs:
13+
test_list += doc_links[v]
14+
'''
15+
16+
test_docs = random.choice(range(len(doc_cnt)), size = 100, replace = False)
17+
18+
#for v in test_links:
19+
for v in test_docs:
20+
for v2 in doc_links[v]:
21+
try:
22+
doc_links[v2].remove(v)
23+
except:
24+
continue
25+
doc_links[v] = []
26+
27+
doc_links_unremoved = cPickle.load(open('doc_links_sym.pkl'))
28+
29+
#model = rtm(30, len(doc_cnt), len(bow), doc_ids, doc_cnt, doc_links, rho = 3000)
30+
#model.posterior_inference(50)
31+
32+
for rho in [0, 10, 10, 100, 100, 1000, 1000, 10000, 10000]:
33+
#for rho in [10000, 100000, 1000000]:
34+
model = rtm(30, len(doc_cnt), len(bow), doc_ids, doc_cnt, doc_links, rho = rho)
35+
model.posterior_inference(30)
36+
print
37+

ptm/rtm_heldout.py

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
import numpy as np
2+
from scipy.special import gammaln, psi
3+
4+
eps = 1e-10
5+
6+
class rtm:
7+
""" implementation of relational topic model by Chang and Blei (2009)
8+
I implemented the exponential link probability function in here
9+
"""
10+
11+
def __init__(self, num_topic, num_doc, num_voca, doc_ids, doc_cnt, doc_links, rho):
12+
self.D = num_doc
13+
self.K = num_topic
14+
self.V = num_voca
15+
16+
self.alpha = 1.
17+
18+
self.gamma = np.random.gamma(100., 1./100, [self.D, self.K])
19+
self.beta = np.random.dirichlet([5]*self.V, self.K)
20+
21+
self.nu = 0
22+
self.eta = np.random.normal(0.,1, self.K)
23+
24+
self.phi = list()
25+
self.pi = np.zeros([self.D, self.K])
26+
27+
for di in xrange(self.D):
28+
unique_word = len(doc_ids[di])
29+
cnt = doc_cnt[di]
30+
self.phi.append(np.random.dirichlet([10]*self.K, unique_word).T) # list of KxW
31+
self.pi[di,:] = np.sum(cnt*self.phi[di],1)/np.sum(cnt*self.phi[di])
32+
33+
self.doc_ids = doc_ids
34+
self.doc_cnt = doc_cnt
35+
self.doc_links = doc_links
36+
self.rho = rho #regularization parameter
37+
38+
def posterior_inference(self, max_iter):
39+
for iter in xrange(max_iter):
40+
self.variation_update()
41+
self.parameter_estimation()
42+
#print self.compute_elbo()
43+
if iter == max_iter-1:
44+
print self.link_prediction()
45+
46+
def compute_elbo(self):
47+
""" compute evidence lower bound for trained model
48+
"""
49+
elbo = 0
50+
51+
e_log_theta = psi(self.gamma) - psi(np.sum(self.gamma, 1))[:,np.newaxis] # D x K
52+
log_beta = np.log(self.beta)
53+
54+
for di in xrange(self.D):
55+
words = self.doc_ids[di]
56+
cnt = self.doc_cnt[di]
57+
58+
elbo += np.sum(cnt * (self.phi[di] * log_beta[:,words])) # E_q[log p(w_{d,n}|\beta,z_{d,n})]
59+
elbo += np.sum((self.alpha - 1.)*e_log_theta[di,:]) # E_q[log p(\theta_d | alpha)]
60+
elbo += np.sum(self.phi[di].T * e_log_theta[di,:]) # E_q[log p(z_{d,n}|\theta_d)]
61+
62+
elbo += -gammaln(np.sum(self.gamma[di,:])) + np.sum(gammaln(self.gamma[di,:])) \
63+
- np.sum((self.gamma[di,:] - 1.)*(e_log_theta[di,:])) # - E_q[log q(theta|gamma)]
64+
elbo += - np.sum(cnt * self.phi[di] * np.log(self.phi[di])) # - E_q[log q(z|phi)]
65+
66+
for adi in self.doc_links[di]:
67+
elbo += np.dot(self.eta, self.pi[di]*self.pi[adi]) # E_q[log p(y_{d1,d2}|z_{d1},z_{d2},\eta,\nu)]
68+
69+
return elbo
70+
71+
def variation_update(self):
72+
#update phi, gamma
73+
e_log_theta = psi(self.gamma) - psi(np.sum(self.gamma, 1))[:,np.newaxis]
74+
75+
new_beta = np.zeros([self.K, self.V])
76+
77+
for di in xrange(self.D):
78+
words = self.doc_ids[di]
79+
cnt = self.doc_cnt[di]
80+
doc_len = np.sum(cnt)
81+
82+
new_phi = np.log(self.beta[:,words]) + e_log_theta[di,:][:,np.newaxis]
83+
84+
gradient = np.zeros(self.K)
85+
for adi in self.doc_links[di]:
86+
gradient += self.eta * self.pi[adi,:] / doc_len
87+
88+
new_phi += gradient[:,np.newaxis]
89+
new_phi = np.exp(new_phi)
90+
new_phi = new_phi/np.sum(new_phi,0)
91+
92+
self.phi[di] = new_phi
93+
94+
self.pi[di,:] = np.sum(cnt * self.phi[di],1)/np.sum(cnt * self.phi[di])
95+
self.gamma[di,:] = np.sum(cnt * self.phi[di], 1) + self.alpha
96+
new_beta[:, words] += (cnt * self.phi[di])
97+
98+
self.beta = new_beta / np.sum(new_beta, 1)[:,np.newaxis]
99+
100+
def parameter_estimation(self):
101+
#update eta, nu
102+
pi_sum = np.zeros(self.K)
103+
104+
num_links = 0.
105+
106+
for di in xrange(self.D):
107+
for adi in self.doc_links[di]:
108+
pi_sum += self.pi[di,:]*self.pi[adi,:]
109+
num_links += 1
110+
111+
num_links /= 2. # divide by 2 for bidirectional edge
112+
pi_sum /= 2.
113+
114+
pi_alpha = np.zeros(self.K) + self.alpha/(self.alpha*self.K)*self.alpha/(self.alpha*self.K)
115+
116+
self.nu = np.log(num_links-np.sum(pi_sum)) - np.log(self.rho*(self.K-1)/self.K + num_links - np.sum(pi_sum))
117+
self.eta = np.log(pi_sum) - np.log(pi_sum + self.rho * pi_alpha) - self.nu
118+
119+
def link_prediction(self):
120+
121+
prediction = []
122+
'''
123+
for v in test_docs:
124+
prediction_sub = dict()
125+
for v2 in range(self.D):
126+
prediction_sub[v2] = np.exp(self.eta.dot(self.pi[v]*self.pi[v2]) + self.nu)
127+
sorted_prediction_sub = sorted(prediction_sub.items(), key = operator.itemgetter(1))[::-1]
128+
sorted_prediction_sub_dict = {k[0] : idx for idx, k in enumerate(sorted_prediction_sub)}
129+
linked_rankings = []
130+
for v3 in doc_links_unremoved[v]:
131+
linked_rankings.append(sorted_prediction_sub_dict[v3])
132+
prediction.append(np.mean(linked_rankings))
133+
'''
134+
135+
for v in test_docs:
136+
predicted_likelihood = np.exp(self.eta.dot((self.pi[v]*self.pi).T) + self.nu)
137+
sorted_p = predicted_likelihood.argsort()[::-1]
138+
linked_rankings = []
139+
for v2 in doc_links_unremoved[v]:
140+
linked_rankings.append(list(sorted_p).index(v2))
141+
prediction.append(np.mean(linked_rankings))
142+
143+
return np.mean(prediction)
144+
145+
def main():
146+
rho = 1
147+
num_topic = 2
148+
num_voca = 6
149+
num_doc = 2
150+
doc_ids = [[0,1,4],[2,3,5]]
151+
doc_cnt = [[2,2,3],[1,3,1]]
152+
doc_links = [[1],[0]] #bidirectional link
153+
model = rtm(num_topic, num_doc, num_voca, doc_ids, doc_cnt, doc_links, rho)
154+
model.posterior_inference(10)
155+
156+
if __name__ == '__main__':
157+
main()

0 commit comments

Comments
 (0)