1 # Todo: since we evaluate _after_ we reestimate, we loose the icharts
2 # made while reestimating. If we had these available, evaluate and
3 # corpus_likelihood would be a lot faster, but since they need to run
4 # _after_ reestimate, we'll have to store an ichart per sentence. So
5 # try storing those icharts in some loc_h_dmv global, and see if it's
6 # faster using space rather than time.
8 from common_dmv
import MPPROOT
, test
, node_str
9 from wsjdep
import WSJDepCorpusReader
11 #HARMONIC_C: 509.637290698, FNONSTOP_MIN: 30.1124584139, FSTOP_MIN: 13.0830178845
12 def initialize_loc_h(tagonlys
):
13 import loc_h_harmonic
# since we need to change constants (is there a better way?)
14 reload(loc_h_harmonic
)
16 # loc_h_harmonic.HARMONIC_C = 380.111684914
17 # loc_h_harmonic.FSTOP_MIN = 13.5744632704
18 # loc_h_harmonic.FNONSTOP_MIN = 34.8939452454
19 loc_h_harmonic
.HARMONIC_C
= 0.0 #120.0 * random.random() # 509.63
20 loc_h_harmonic
.STOP_C
= 1.0 #3.0 * random.random()
21 loc_h_harmonic
.NSTOP_C
= 0.1 #5.0 * random.random() # 0.1
22 loc_h_harmonic
.FSTOP_MIN
= 10.0 #20.0 * random.random() # 13.08
23 # $C_A=0; C_S=1;C_N=0.1;C_M=10$
24 loc_h_harmonic
.RIGHT_FIRST
= 1.0
25 loc_h_harmonic
.OLD_STOP_CALC
= False
27 HARMONIC_C: %s, STOP_C: %s, NSTOP_C: %s, FSTOP_MIN: %s
28 RIGHT_FIRST: %s, OLD_STOP_CALC: %s'''%(loc_h_harmonic
.HARMONIC_C
,
29 loc_h_harmonic
.STOP_C
,
30 loc_h_harmonic
.NSTOP_C
,
31 loc_h_harmonic
.FSTOP_MIN
,
32 loc_h_harmonic
.RIGHT_FIRST
,
33 loc_h_harmonic
.OLD_STOP_CALC
)
34 g
= loc_h_harmonic
.initialize(tagonlys
)
37 def initialize_uniform_loc_h(tagonlys
):
39 return loc_h_harmonic
.uniform_init(tagonlys
)
41 def initialize_cnf(tagonlys
):
42 import cnf_harmonic
# since we need to change constants (is there a better way?)
44 cnf_harmonic
.HARMONIC_C
= 0.0
45 cnf_harmonic
.FNONSTOP_MIN
= 25
46 cnf_harmonic
.FSTOP_MIN
= 5
47 return cnf_harmonic
.initialize(tagonlys
)
50 def test_likelihood(reestimate
, initialize
, inner_sent
,
51 corpus_size
=20, corpus_offset
=1000, iterations
=4, EVAL
=False):
52 def run_IO(g
, iterations
, tagonlys
, tags_and_parses
):
53 sumlog
,msg
= corpus_likelihood(g
, tagonlys
)
56 g
.E
= evaluate(g
, tags_and_parses
)
58 for i
in range(iterations
):
59 g
= reestimate(g
, tagonlys
)
60 print "reestimation number %d done\n"%i
62 g
.E
= evaluate(g
, tags_and_parses
)
65 sumlog
,msg
= corpus_likelihood(g
, tagonlys
)
66 if sumlog
< prev_sumlog
:
67 raise Exception, msg
+"but previous was %s"%prev_sumlog
69 # since I want to be able to do stuff with it afterwards:
70 from pickle
import dump
# let us say g = pickle.load(open('..','rb'))
71 filehandler
= open('current_grammar.obj','w')
77 def corpus_likelihood(g
, tagsonly
):
81 p_sent
= inner_sent(g
, sent
, {})
83 print "%s had zero probability!"%sent
86 avg
= sumlog
/ len(tagsonly
)
87 return (sumlog
, "Sum of log P_{sentence}: %.4f (should move towards 0), avg: %s"%(sumlog
,avg
))
89 reader
= WSJDepCorpusReader(None)
90 tagonlys
= reader
.tagonly_sents()[corpus_offset
:corpus_offset
+corpus_size
]
91 tags_and_parses
= reader
.tagged_and_parsed_sents()[corpus_offset
:corpus_offset
+corpus_size
]
93 print "\ninitializing %d sentences..." % corpus_size
,
94 g
= initialize(tagonlys
)
97 g
= run_IO(g
, iterations
, tagonlys
, tags_and_parses
) # make iterations argument, todo
101 print "underproposed:"
102 pprint
.pprint(g
.E
.underproposed
)
103 print "overproposed:"
104 pprint
.pprint(g
.E
.overproposed
)
110 "Just a class to hold evaluation-relevant information, sum it up, and print it."
112 self
.underproposed
, self
.overproposed
= {}, {}
113 self
.R
, self
.R_r
, self
.P
, self
.P_r
= {}, {}, {}, {}
114 for nd
in ['num', 'den']:
115 self
.R
[nd
], self
.R_r
[nd
], self
.P
[nd
], self
.P_r
[nd
] = 0, 0, 0, 0
117 self
.unrooted
= 0 # parses where we couldn't add_root
118 self
.double_heads
= 0 # parses w/ two heads to one argument
119 self
._precision
, self
._recall
, self
._precision
_r
, self
._recall
_r
= 0.0, 0.0, 0.0, 0.0
120 self
._F
1, self
._F
1_r
= 0.0, 0.0
122 def calc_F1_P_R(self
):
123 "F1 = (2 * P * R)/(P + R), harmonic avg. of P and R"
124 self
._recall
= float(self
.R
['num']) / float(self
.R
['den'])
125 self
._precision
= float(self
.P
['num']) / float(self
.P
['den'])
126 self
._recall
_r
= float(self
.R
['num']+self
.R_r
['num']) / \
127 float(self
.R
['den']+self
.R_r
['den'])
128 self
._precision
_r
= float(self
.P
['num']+self
.P_r
['num']) / \
129 float(self
.P
['den']+self
.P_r
['den'])
131 if (self
._precision
+ self
._recall
) > 0.0:
132 self
._F
1 = (2 * self
._recall
* self
._precision
) / (self
._precision
+ self
._recall
)
133 if (self
._precision
_r
+ self
._recall
_r
) > 0.0:
134 self
._F
1_r
= (2 * self
._recall
_r
* self
._precision
_r
) / (self
._precision
_r
+ self
._recall
_r
)
138 R_rnum
= self
.R
['num']+self
.R_r
['num']
139 R_rden
= self
.R
['den']+self
.R_r
['den']
140 P_rnum
= self
.P
['num']+self
.P_r
['num']
141 P_rden
= self
.P
['den']+self
.P_r
['den']
142 str_vals
= (self
.P
['num'],self
.P
['den'],self
._precision
, P_rnum
,P_rden
,self
._precision
_r
,
143 self
.R
['num'],self
.R
['den'],self
._recall
, R_rnum
,R_rden
,self
._recall
_r
,
144 self
._F
1, self
._F
1_r
, self
.unrooted
, self
.double_heads
)
145 regular_str
= '''P: %5d/%5d = %s | P_r: %5d/%5d = %s
146 R: %5d/%5d = %s | R_r: %5d/%5d = %s
147 F1: %s | F1_r: %s (unrooted gold parses: %d, double-headed: %d)'''%str
_vals
149 tex_str_vals
= tuple([p
* 100 for p
in (self
._precision
,self
._precision
_r
,self
._recall
,self
._recall
_r
,self
._F
1,self
._F
1_r
)])
150 tex_str
= "$C_A=; C_S=;C_N=;C_M=$ & %.1f (%.1f) & %.1f (%.1f) & %.1f (%.1f) \\"%tex_str_vals
152 return tex_str
# todo make variable
156 def evaluate(g
, tagged_and_parsed_sents
):
157 ''' tagged_and_parsed_sents is a list of pairs:
158 (tagonly_sent, parsed_sent)
160 R_num += 1 if pair from parsed is in mpp
161 R_den += 1 per pair from parsed
163 P_num += 1 if pair from mpp is in parsed
164 P_den += 1 per pair from mpp '''
165 from loc_h_dmv
import mpp
166 from wsjdep
import add_root
169 for sent
, gold_parse
in tagged_and_parsed_sents
:
170 if len(sent
)-1 != len(gold_parse
):
173 mpp_sent
= mpp(g
, sent
)
174 try: gold_parse
= add_root(gold_parse
)
175 except RuntimeError: E
.unrooted
+= 1
177 for pair
in gold_parse
:
179 if pair
[0] == MPPROOT
: dict = E
.R_r
181 if pair
in mpp_sent
: dict['num'] += 1
183 try: E
.underproposed
[pair
] += 1
184 except KeyError: E
.underproposed
[pair
] = 1
186 for pair
in mpp_sent
:
188 if pair
[0] == MPPROOT
: dict = E
.P_r
190 if pair
in gold_parse
: dict['num'] += 1
192 try: E
.overproposed
[pair
] += 1
193 except KeyError: E
.overproposed
[pair
] = 1
199 def compare_loc_h_cnf():
200 reader
= WSJDepCorpusReader(None)
203 tagonlys
= reader
.tagonly_sents()[corpus_offset
:corpus_offset
+corpus_size
]
205 import loc_h_harmonic
, cnf_harmonic
206 g_l
= loc_h_harmonic
.initialize(tagonlys
)
207 g_c
= cnf_harmonic
.initialize(tagonlys
)
210 (g_l
.p_ROOT
.iteritems(), g_c
.p_ROOT
),
211 (g_c
.p_ROOT
.iteritems(), g_l
.p_ROOT
),
212 (g_l
.p_STOP
.iteritems(), g_c
.p_STOP
),
213 (g_c
.p_STOP
.iteritems(), g_l
.p_STOP
),
214 (g_l
.p_ATTACH
.iteritems(), g_c
.p_ATTACH
),
215 (g_c
.p_ATTACH
.iteritems(), g_l
.p_ATTACH
)]
216 for a_items
, b
in initials
:
218 if k
not in b
.keys(): raise Warning, "a[%s]=%s, but %s not in b"(k
,v
,k
)
219 if (k
,v
) not in b
.iteritems(): raise Warning, "a[%s]=%s, but b[%s]=%s"(k
,v
,k
,b
[k
])
222 import loc_h_dmv
, cnf_dmv
223 from common_dmv
import GOR
224 for sent
in tagonlys
:
225 ochart_l
, ochart_c
, ichart_l
, ichart_c
= {},{},{},{}
226 i_l
= loc_h_dmv
.inner_sent(g_l
, sent
, ichart_l
)
227 i_c
= cnf_dmv
.inner_sent(g_c
, sent
, ichart_c
)
228 test( "%s"%i_l, "%s"%i_c
, "i_l","i_c")
230 for loc_w
,w
in enumerate(sent
):
231 w_node
= (GOR
, g_l
.tagnum(w
))
232 o_l
= loc_h_dmv
.outer(loc_w
,loc_w
+1,w_node
,loc_w
, g_l
, sent
, ichart_l
,ochart_l
)
233 o_c
= cnf_dmv
.outer(loc_w
,loc_w
+1,w_node
, g_c
, sent
, ichart_c
,ochart_c
)
234 print "%s, %s, %s"%(sent
,node_str(w_node
),loc_w
)
235 test("%s"%o_l, "%s"%o_c
, "o_l(0,1,(GOR,%s),%d,...)"%(w
,loc_w
),"o_c")
237 # end compare_loc_h_cnf()
240 def init_nothing(g
,H
,S
,N
,M
):
242 HARMONIC_C: %s, STOP_C: %s, NSTOP_C: %s, FSTOP_MIN: %s'''%(H
,S
,N
,M
)
243 return lambda corpus
:g
245 def rnd_grammars_test():
251 g
= test_likelihood(loc_h_dmv
.reestimate
,
253 loc_h_dmv
.inner_sent
,
258 rnd_grammars0
+= [(g
, g
.HARMONIC_C
, g
.STOP_C
, g
.NSTOP_C
, g
.FSTOP_MIN
)]
260 rnd_grammars1
= [(test_likelihood(loc_h_dmv
.reestimate
,
261 init_nothing(g
,H
,S
,N
,M
),
262 loc_h_dmv
.inner_sent
,
268 for g
,H
,S
,N
,M
in rnd_grammars0
]
269 rnd_grammars2
= [(test_likelihood(loc_h_dmv
.reestimate
,
270 init_nothing(g
,H
,S
,N
,M
),
271 loc_h_dmv
.inner_sent
,
277 for g
,H
,S
,N
,M
in rnd_grammars1
]
280 if __name__
== "__main__":
288 print "\ntrying reestimate v.1 ##############################"
289 g
= test_likelihood(loc_h_dmv
.reestimate
,
291 loc_h_dmv
.inner_sent
,
298 # print "\ntrying reestimate v.2 ##############################"
299 # g = test_likelihood(loc_h_dmv.reestimate2,
301 # loc_h_dmv.inner_sent,
305 # print "main.py: done"
309 # compare_loc_h_cnf()
312 # print "\ntrying cnf-reestimate ##############################"
313 # g = test_likelihood(cnf_dmv.reestimate,
315 # cnf_dmv.inner_sent,