Neulich wurde mir am Semina des Instituts für Statistische Mathematik ein kontinuierliches Raumthemenmodell beigebracht. Im Vergleich zu dem Generierungsmodell, bei dem die konventionelle Latent Dirichlet Allocation ein gemischtes Modell verwendet (Summenmodell) Das kontinuierliche Raumthemenmodell ist ein Generierungsmodell unter Verwendung von RBM (Produktmodell). Laut dem Papier ist die Leistung besser als bei LDA.
Weitere Informationen finden Sie im folgenden Dokument http://chasen.org/~daiti-m/paper/nl213cstm.pdf
Es sieht interessant aus, daher möchte ich es implementieren und überprüfen.
Ursprünglich war es auf der CPU implementiert, aber es dauerte mehr als 10 Stunden für eine Epoche mit 1000 Sätzen und 8000 Wörtern. Es wurde mit GPU (Cupy) erneut ausgeführt und es wurde ungefähr 1 Epoche 1 Stunde.
cstm_gpu.py
import numpy as np
from chainer import cuda
xp = cuda.cupy
# Γ(α + n) / Γ(α) = (α + (n-1) ) * (α + (n-2)) * ... * (α + 1) * α
#Da der Wert groß wird, erstellen Sie ein Protokoll
# alpha_arr GPU
# n_arr CPU
# n_arr_gpu GPU
def log_gamma_div_gpu(alpha_arr, n_arr, n_arr_gpu):
n_max = np.max(n_arr)
alpha_arr_tmp = xp.copy(alpha_arr)
alpha_arr_tmp[np.where(n_arr==0)] = 1
log_sum_arr = xp.log(alpha_arr_tmp)
for i in range(1,int(n_max)):
n_tmp = xp.where(n_arr_gpu>i+0.5,i,0)
alpha_tmp = xp.where(n_tmp < 0.5, 1 , alpha_arr_tmp + n_tmp)
log_sum_arr += xp.log(alpha_tmp)
return log_sum_arr
def log_gamma_div_cpu(alpha_arr, n_arr):
if isinstance(alpha_arr, np.float64) != 1:
alpha_arr_cpu = cuda.to_cpu(alpha_arr)
else:
alpha_arr_cpu = alpha_arr
n_max = np.max(n_arr)
alpha_arr_tmp_cpu = np.where(alpha_arr_cpu!=0,alpha_arr_cpu,1)
log_sum_arr_cpu = np.log(alpha_arr_tmp_cpu)
for i in range(1,int(n_max)):
n_tmp = np.where(n_arr>i,i,0)
alpha_tmp_cpu = np.where(n_tmp==0, 1 , alpha_arr_tmp_cpu + n_tmp)
log_sum_arr_cpu += np.log(alpha_tmp_cpu)
return log_sum_arr_cpu
class AlphaClass:
#Lernvariablen ersetzen
def __init__(self,G0):
self.G0 = cuda.to_gpu(G0)
#Berechnen Sie α
#Rückgabewertform(Anzahl der Sätze,Anzahl der Wörter)
def calculate_alpha(self,alpha0,w_emb,d_emb):
tmp = d_emb.dot(w_emb.transpose())
alpha = alpha0 * self.G0 * xp.exp(tmp)
return alpha
class ProbClass:
def __init__(self, n):
self.n = n
self.n_gpu = cuda.to_gpu(n)
#Berechnen Sie die gleichzeitige Wahrscheinlichkeit für jedes Dokument für alle Dokumente
#Rückgabewertform(Anzahl der Sätze,)
def calculate_prob_log(self,alpha):
alpha2 = xp.copy(alpha)
alpha2[np.where(self.n==0)] = 0
tmp1 = log_gamma_div_cpu(xp.sum(alpha2,axis=1),np.sum(self.n,axis=1))
tmp2 = xp.sum(log_gamma_div_gpu(alpha2,self.n,self.n_gpu),axis=1)
prob = xp.asarray(-tmp1) + tmp2
return prob
def calculate_alpha_index(alpha0,G0,w_emb,d):
tmp = d.dot(w_emb.transpose())
alpha = alpha0 * G0 * np.exp(tmp)
return alpha
#Berechnen Sie die gleichzeitige Wahrscheinlichkeit für jedes Dokument
#Rückgabewert Wert
def calculate_prob_log_index(alpha,n):
alpha2 = np.copy(alpha)
alpha2[np.where(n==0)] = 0
tmp1 = log_gamma_div_cpu(np.sum(alpha2),np.sum(n))
tmp2 = np.sum(log_gamma_div_cpu(alpha2,n))
prob = - tmp1 + tmp2
return prob
def mh_accept(log_ll_old,log_ll_new):
if log_ll_old < log_ll_new:
return 1
else:
p = np.exp(cuda.to_cpu(log_ll_new-log_ll_old))
return np.random.binomial(1,p)
train_cstm_gpu.py
alpha0 = 1.0
w_emb = np.random.randn(Anzahl der Wörter,Anzahl der Einheiten)
d_emb = np.random.randn(Anzahl der Sätze,Anzahl der Einheiten)
wordcntbydoc =Anzahl der häufigen Wörter in jedem Satz
G0 =Anzahl der häufigen Wörter in allen Sätzen/Summe der Anzahl häufiger Wörter
sigma_doc = 0.01
sigma_word = 0.02
sigma_alpha = 0.2
alphaclass = cstm.AlphaClass(G0)
probclass = cstm.ProbClass(wordcntbydoc)
def calculate_prob_log_all(alpha0,w,d):
alpha = alphaclass.calculate_alpha(alpha0,w,d)
prob = probclass.calculate_prob_log(alpha)
return prob
prob = calculate_prob_log_all(alpha0,xp.asarray(w_emb),xp.asarray(d_emb))
print("prob={}".format(xp.sum(prob)))
begin_time = time.time()
for epoch in range(0,args.epoch):
logwrite('epoch=' + str(epoch))
w_perm = np.random.permutation(n_vocab)
d_perm = np.random.permutation(n_wid)
for i in d_perm:
d_i = d_emb[i] + sigma_doc * np.random.randn(args.unit)
alpha_new = cstm.calculate_alpha_index(alpha0,G0,w_emb,d_i)
prob_new = cstm.calculate_prob_log_index(alpha_new, wordcntbydoc[i])
new_flag = cstm.mh_accept(prob_old,prob_new)
if new_flag == 1:
d_emb[i] = d_i
prob[i] = prob_new
logwrite(" doc i={}:ll={}".format(i,xp.sum(prob)))
end_time = time.time()
duration = end_time - begin_time
prob = calculate_prob_log_all(xp.asarray(alpha0),xp.asarray(w_emb),xp.asarray(d_emb))
logwrite("doc result={}".format(xp.sum(prob)))
logwrite('doc: {:.2f} sec'.format(duration))
begin_time = time.time()
for i in w_perm:
w_emb_new = xp.copy(w_emb)
w_emb_new[i] = w_emb[i] + sigma_word * np.random.randn(args.unit)
prob_new = calculate_prob_log_all(xp.asarray(alpha0),xp.asarray(w_emb_new),xp.asarray(d_emb))
new_flag = cstm.mh_accept(xp.sum(prob),xp.sum(prob_new))
if new_flag == 1:
prob = xp.copy(prob_new)
w_emb = np.copy(w_emb_new)
logwrite(" word i={}:ll={}".format(i,xp.sum(prob)))
end_time = time.time()
duration = end_time - begin_time
prob = calculate_prob_log_all(xp.asarray(alpha0),xp.asarray(w_emb),xp.asarray(d_emb))
logwrite("word result={}".format(xp.sum(prob)))
logwrite('word: {:.2f} sec'.format(duration))
begin_time = time.time()
z = sigma_alpha * np.random.randn(1)
alpha0_new = alpha0 * np.exp(z)
prob_new = calculate_prob_log_all(xp.asarray(alpha0_new),xp.asarray(w_emb),xp.asarray(d_emb))
new_flag = cstm.mh_accept(xp.sum(prob),np.sum(prob_new))
if new_flag == 1:
alpha0 = alpha0_new
prob = xp.copy(prob_new)
logwrite(" alpha0 : ll={} alpha0={}".format(xp.sum(prob),alpha0))
end_time = time.time()
duration = end_time - begin_time
prob = calculate_prob_log_all(xp.asarray(alpha0),xp.asarray(w_emb),xp.asarray(d_emb))
logwrite("alpha0 result={}".format(xp.sum(prob)))
logwrite('alpha0: {:.2f} sec'.format(duration))
begin_time = time.time()
logwrite('Save to pkl epoch=' + str(epoch) )
result_all = [alpha0,w_emb,d_emb]
file1 = resultdir + "/result_epoch_" + "{0:0>3}".format(epoch) + ".pkl"
with open(file1, 'wb') as output1:
six.moves.cPickle.dump(result_all, output1, -1)
Die Berechnung der Gammafunktion wurde erzwungen, um mit der GPU zu beschleunigen. Entspricht die Formel des Papiers dem Wert der Quelle, da sie einmal implementiert wurde? Ich möchte dies während eines Bestätigungstests überprüfen.
Recommended Posts