Skip to content

Commit c84ccd2

Browse files
committed
new format - arbitrary attributes.
Also ability to show multiple graphs at once and we don't start timing until after a whole step.
1 parent 2140abe commit c84ccd2

File tree

2 files changed

+91
-19
lines changed

2 files changed

+91
-19
lines changed

results/Readme.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,18 @@ Two functions are provided which are called by the training routine:
99
#### `results.startRun`
1010
This is called before any training, and stores information about the run for future reference. It also creates the database file (by default `results.sqlite`) if it doesn't exist.
1111

12-
The supplied information I store for each run are pretty much the arguments of this function and the columns of the table RUNS. Exception: `callerFilePath` is a list of filenames whose contents we store - e.g. the code. I use the nonemptiness of `continuation` to indicate that the model was not trained from scratch, but from the saved weights of the previous run. `architecture` and `solver` are basically assumed in diffRuns and describeRun to be long JSON strings. You can change any of this.
12+
`attribs` is a dictionary of properties to store for the run, `callerFilePath` is a list of filenames whose contents we store - e.g. the code. `continuation` is a string - I use the nonemptiness of `continuation` to indicate that the model was not trained from scratch, but from the saved weights of the previous run. `architecture` and `solver` are basically assumed in diffRuns and describeRun to be long JSON strings. You can change any of this.
1313

1414
#### `results.step`
1515
This stores the reported training and test objective and accuracy from each step of training.
1616
These are stored in the STEPS table.
17-
The time for the first 10 steps is remembered in the steps table.
17+
The time for the first 10 steps (excluding the first) is remembered in the steps table.
1818

19-
These functions are also available in lua after something like this
19+
Similar functions are also available in lua after something like this.
2020
```
2121
results = require 'results'
2222
```
23+
2324
##warning
2425
Only one process should modify the database at any one time; you cannot train two models to the same database. But you can have as many processes as you like connected to the database and using the query functions, even during training.
2526

results/results.py

Lines changed: 87 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@
2424
nrun = 0
2525
nsteps = 0
2626
starttime = 0
27+
oldColumns = True
2728

2829
#todo - be flexible about the results column
2930
# - keep a global variable of their names, prettyname, bigIsGood
3031

3132

32-
def startRun(repnname, repnlength, continuation, batchTr, batchTe, layertype, layers, width, architecture, solver, callerFilePath):
33+
def startRun(continuation, attribs, architecture, solver, callerFilePath):
3334
global nrun
34-
global starttime
3535
global filecontents
3636
filecontents=""
3737
if callerFilePath is not None:
@@ -44,32 +44,43 @@ def getC(f):
4444
getC(f)
4545
else:
4646
getC(callerFilePath)
47-
setup=["create table if not exists RUNS(COUNT INTEGER PRIMARY KEY, TIME TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL, REPN TEXT, REPNLENGTH INT, CONTINUATION TEXT, BATCHTR INT, BATCHTE INT, LAYERTYPE TEXT, LAYERS INT, WIDTH INT, ARCHITECTURE TEXT, SOLVER TEXT, CODE TEXT)", #these default keys start at 1
47+
runColList="(COUNT INTEGER PRIMARY KEY, TIME TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL, REPN TEXT, REPNLENGTH INT, CONTINUATION TEXT, BATCHTR INT, BATCHTE INT, LAYERTYPE TEXT, LAYERS INT, WIDTH INT, ARCHITECTURE TEXT, SOLVER TEXT, CODE TEXT)"
48+
if not oldColumns:
49+
runColList="(COUNT INTEGER PRIMARY KEY, TIME TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL, CONTINUATION TEXT, ARCHITECTURE TEXT, SOLVER TEXT, CODE TEXT)"
50+
setup=["create table if not exists RUNS"+runColList,#these default keys start at 1
4851
"create table if not exists STEPS(STEP INTEGER PRIMARY KEY, RUN int, OBJECTIVE real, TRAINACC real, TESTOBJECTIVE real, TESTACC REAL )",
49-
"create table if not exists TIMES(RUN INT, TIME real)" # stores the time of the tenth step of each run, allowing speed to be measured
52+
"create table if not exists TIMES(RUN INT, TIME real)", # stores the time of the tenth step of each run, allowing speed to be measured
53+
"create table if not exists ATTRIBS(RUN INT, NAME TEXT, ISRESULT INT, VALUE TEXT)"
5054
]
51-
infoquery = "insert into RUNS (REPN, REPNLENGTH, CONTINUATION, BATCHTR, BATCHTE, LAYERTYPE, LAYERS, WIDTH, ARCHITECTURE, SOLVER, CODE) VALUES (?,?,?,?,?,?,?,?,?,?,?)"
52-
info = (repnname, repnlength, continuation, batchTr, batchTe, layertype, layers, width, architecture, solver, filecontents)
55+
infoquery = "insert into RUNS (CONTINUATION, ARCHITECTURE, SOLVER, CODE) VALUES (?,?,?,?)"
56+
info = (continuation, architecture, solver, filecontents)
57+
attribquery = "insert into ATTRIBS(RUN, NAME, ISRESULT, VALUE) VALUES (?,?,0,?)"
5358
if useCPP:
5459
for s in setup:
5560
report.resultless(s)
5661
report.sink(infoquery,info)
5762
nrun = report.lastRow()
63+
for k,v in sorted(attribs.items()):
64+
report.sink(attribquery,(nrun,k,v))
5865
else:
5966
c = con.cursor()
6067
for s in setup:
6168
c.execute(s)
6269
c.execute(infoquery, info)
6370
nrun = c.lastrowid
71+
c.executemany(attribquery,[([nrun]+list(i)) for i in sorted(attribs.items())])
6472
con.commit()
65-
starttime = datetime.datetime.now()
6673

6774
#store elapsed time with each step?
75+
#We store the time taken for 10 steps, but actually we count steps 2 to 11, because if you use
76+
#keras the first step may include some of the compilation
6877
def step(obj, train, objte, test):
69-
global nsteps
78+
global nsteps, starttime
7079
q = [("insert into steps values (NULL, ?, ?, ?, ?, ?)",(nrun,obj,train,objte,test))]
7180
nsteps = 1 + nsteps
72-
if nsteps == 10:
81+
if nsteps == 1:
82+
starttime = datetime.datetime.now()
83+
if nsteps == 11:
7384
#c.execute("insert into TIMES (RUN) VALUES (?)", (nrun,))
7485
q.append(("insert into TIMES VALUES (?,?)", (nrun, (datetime.datetime.now()-starttime).total_seconds())))
7586

@@ -82,6 +93,17 @@ def step(obj, train, objte, test):
8293
c.execute(sql,data)
8394
con.commit()
8495

96+
def addResultAttribute(name, value):
97+
q=[("insert into ATTRIBS(RUN, NAME, ISRESULT, VALUE) VALUES (?,?,1,?)",(nrun, name, value))]
98+
c=con.cursor()
99+
if True:
100+
count = c.execute("select count(*) from ATTRIBS where run = ? and name = ?",(nrun,name)).fetchone()[0]
101+
if count>0:
102+
raise RuntimeError("attribute already set:",name)
103+
for sql, data in q:
104+
c.execute(sql,data)
105+
con.commit()
106+
85107
def signoff():
86108
con.close()
87109

@@ -116,7 +138,12 @@ def pushplot(plt,title=""):
116138
plt.savefig("/home/jeremyr/Dropbox/phd/graphs/"+time.strftime("%Y%m%d-%H%M%S")+title)
117139
plt.close()
118140
else:
119-
plt.show()
141+
multiwindow=False
142+
if multiwindow:#multiple graphs, non blocking
143+
plt.show(block=False)
144+
plt.figure()
145+
else:
146+
plt.show()
120147

121148
def runList():
122149
c=con.cursor()
@@ -132,19 +159,42 @@ def runList():
132159

133160
def runList1():
134161
c=con.cursor()
162+
if not oldColumns:
163+
raise RuntimeError("runList1 not available in the new format")
135164
b=c.execute("select repnlength, repn, count(step), min(objective), max(trainacc), max(testacc) from runs r left join steps s on r.count=s.run group by count").fetchall()
136165
for j in b:
137166
print(j)
138167

168+
def _listAttribs(wantRes):
169+
c=con.cursor()
170+
if wantRes is None:
171+
a = c.execute("select distinct(name) from ATTRIBS").fetchall()
172+
else:
173+
a = c.execute("select distinct(name) from ATTRIBS where ISRESULT = ?", (wantRes,)).fetchall()
174+
b=sorted([i[0] for i in a])
175+
return b
176+
177+
def _getAttribAsStr(run,name):
178+
c=con.cursor()
179+
a = c.execute("select value from ATTRIBS where run = ? and name = ?",(run,name)).fetchall()
180+
for i in a:#there should only be one if there are any
181+
return str(i[0])
182+
return ""
183+
139184
#architectureLike: if set to 5, only print info for runs with the same network as the one used in run 5
140-
def runList2(avgLength=None, doPrint = True, runFrom=None, architectureLike=None): #with times
185+
#doAttribs: None means all attribs are included, a list means those attributes are included,
186+
# True or False mean only the result or nonresult ones.
187+
def runList2(avgLength=None, doPrint = True, runFrom=None, architectureLike=None, doAttribs=None): #with times
188+
attribs = doAttribs if type(doAttribs)==list else _listAttribs(doAttribs)
141189
if avgLength == None:
142190
avgLength = movingAvgLength
143191
c=con.cursor()
144192
b=[]
145193
archClause = ""
146194
masterQueryArgs = None
147195
if architectureLike is not None:
196+
if not oldColumns:
197+
raise RuntimeError("no architecture search with new format")
148198
# architectureStr = c.execute("select architecture from runs where count = ?",(architectureLike,)).fetchone()[0]
149199
# archClause = "where architecture = ?"
150200
# masterQueryArgs = (architectureStr,)
@@ -153,18 +203,27 @@ def runList2(avgLength=None, doPrint = True, runFrom=None, architectureLike=None
153203
if runFrom is not None:
154204
archClause = archClause + " and count >= " + str(runFrom)
155205
runFrom = None
156-
masterQuery = "select count, repnlength, repn, case when length(continuation)>0 then '+' else '' end || count(step), (select time from times where run = r.count) from runs r left join steps s on r.count=s.run %s group by count" % (archClause if runFrom is None else ("where count>= "+str(runFrom)))
206+
masterQuery = "select count, "+("repnlength, repn," if oldColumns else "") +" case when length(continuation)>0 then '+' else '' end || count(step), (select time from times where run = r.count) from runs r left join steps s on r.count=s.run %s group by count" % (archClause if runFrom is None else ("where count>= "+str(runFrom)))
157207
if masterQueryArgs is None:
158208
bb=c.execute(masterQuery).fetchall()
159209
else:
160210
bb=c.execute(masterQuery,masterQueryArgs).fetchall()
161211
for rec in bb:
162212
values = c.execute("select objective,trainacc,testacc from steps where run=? order by step",(rec[0],))
163213
values = [i for i in values]
164-
def avgs(idx): return movingAverage([i[idx] for i in values],False,avgLength) if len(values)>=avgLength else [None]
165-
b.append(rec[:4] + (numpy.amin(avgs(0)),numpy.amax(avgs(1)),numpy.amax(avgs(2)),rec[4]))
214+
def bestAvg(idx,highIsBad):
215+
if len(values)<avgLength:
216+
return None
217+
s=replaceSeriesWithMovingAverage_([i[idx] for i in values],avgLength,highIsBad)
218+
return (numpy.amin if highIsBad else numpy.amax)(s)
219+
attribValues=tuple(_getAttribAsStr(rec[0],att) for att in attribs)
220+
b.append(rec[:4] + (bestAvg(0,True),bestAvg(1,False),bestAvg(2,False))+attribValues)
166221
if doPrint:
167-
print (tabulate.tabulate(b,headers=["","repLen","repn","steps","objective","trainAcc","testAcc","10StepTime"]))
222+
if oldColumns:
223+
headers=["","repLen","repn","steps","objective","trainAcc","testAcc","10StepTime"]+attribs
224+
else:
225+
headers=["", "steps","objective","trainAcc","testAcc","10StepTime"]+attribs
226+
print (tabulate.tabulate(b,headers=headers))
168227
else:
169228
return b
170229

@@ -193,6 +252,15 @@ def diffRuns(x,y, pretty=1):
193252
print (x1)
194253
print (y1)
195254
dif = [(d[0],a,b) for (a,b,d) in zip(xx,yy,q.description) if (a!=b)]
255+
xxx = [i for i in c.execute("select name,value from attribs where run = ?", (x,)).fetchall()]
256+
yyy = [i for i in c.execute("select name,value from attribs where run = ?", (y,)).fetchall()]
257+
labx= [k for k,v in xxx]
258+
laby= [k for k,v in yyy]
259+
dx=dict(xxx)
260+
dy=dict(yyy)
261+
shared=[i for i in labx if i in laby]
262+
dif=(dif+[(i,dx[i],dy[i]) for i in shared if dx[i]!=dy[i]]+[(i,"",dy[i]) for i in laby if i not in shared]+
263+
[(i,dx[i],"") for i in labx if i not in shared])
196264
print (tabulate.tabulate(dif))
197265

198266
def describeRun(run):
@@ -206,7 +274,9 @@ def describeRun(run):
206274
x1=printJSON_nicely(x1)
207275
pydoc.pager(x1)
208276
data = [(d[0],a) for a,d in zip(xx,q.description)]
209-
print (tabulate.tabulate(data))
277+
data2=c.execute("select name,value from attribs where run = ?", (run,)).fetchall()
278+
print (tabulate.tabulate(data+[i for i in data2]))
279+
210280

211281
def lastSteps(_pager=False, _rtn=False):
212282
c=con.cursor()
@@ -274,6 +344,7 @@ def deleteRun(run):
274344
c.execute("delete from STEPS where run = ?", (run,))
275345
c.execute("delete from TIMES where run = ?", (run,))
276346
c.execute("delete from RUNS where count = ?", (run,))
347+
c.execute("delete from ATTRIBS where run = ?", (run,))
277348
con.commit()
278349

279350
def _runToStr(run):

0 commit comments

Comments
 (0)