svmlab 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/README +219 -0
- data/lib/arraymethods.rb +87 -0
- data/lib/irb.history +100 -0
- data/lib/libsvmdata.rb +122 -0
- data/lib/svmfeature.rb +337 -0
- data/lib/svmfeature2.rb +98 -0
- data/lib/svmlab-config.rb +215 -0
- data/lib/svmlab-irb.rb +98 -0
- data/lib/svmlab-optim.rb +556 -0
- data/lib/svmlab-plot.rb +170 -0
- data/lib/svmlab.rb +365 -0
- data/lib/svmprediction.rb +176 -0
- data/lib/test.cfg +12 -0
- data/lib/test.rb +5 -0
- data/lib/testdata +3 -0
- data/lib/texput.log +20 -0
- data/lib/tmp.irb.rc +81 -0
- data/lib/v6.cfg +124 -0
- metadata +102 -0
data/lib/svmlab-irb.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'irb/completion'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'svmlab'
|
4
|
+
|
5
|
+
#require 'wirble'
|
6
|
+
#Wirble.init
|
7
|
+
#Wirble.colorize
|
8
|
+
|
9
|
+
#IRB.conf[:PROMPT][:SVMLab] = { # name of prompt mode
|
10
|
+
# :PROMPT_I => "SVMLab:%03n:%i> ", # normal prompt
|
11
|
+
# :PROMPT_S => "SVMLab:%03n:%i%l ", # prompt for continuing strings
|
12
|
+
# :PROMPT_C => "SVMLab:%03n:%i* ", # prompt for continuing statement
|
13
|
+
# :RETURN => " ==>%s\n" # format to return value
|
14
|
+
#}
|
15
|
+
ANSI_RESET = "\033[0m"
|
16
|
+
ANSI_GREEN = "\033[2;32m"
|
17
|
+
ANSI_BLUE = "\033[2;34m"
|
18
|
+
|
19
|
+
IRB.conf[:PROMPT][:SVMLab] = { # name of prompt mode
|
20
|
+
#:PROMPT_I => "#{ANSI_BLUE}SVMLab>> #{ANSI_RESET}", # normal prompt
|
21
|
+
:PROMPT_I => "SVMLab > ", # normal prompt
|
22
|
+
:PROMPT_S => " %l ", # prompt for continuing strings
|
23
|
+
:PROMPT_C => " > ", # prompt for continuing statement
|
24
|
+
#:RETURN => "#{ANSI_GREEN} ==> %s\n#{ANSI_RESET}" # format to return value
|
25
|
+
:RETURN => " ==> %s\n" # format to return value
|
26
|
+
}
|
27
|
+
|
28
|
+
IRB.conf[:PROMPT_MODE] = :SVMLab
|
29
|
+
|
30
|
+
|
31
|
+
# Sebastian Delmont
|
32
|
+
# Pretty print methods
|
33
|
+
ANSI_BOLD = "\033[1m"
|
34
|
+
#ANSI_RESET = "\033[0m"
|
35
|
+
ANSI_LGRAY = "\033[0;37m"
|
36
|
+
ANSI_GRAY = "\033[1;30m"
|
37
|
+
|
38
|
+
def pm(obj, *options) # Print methods
|
39
|
+
methods = obj.methods
|
40
|
+
methods -= Object.methods unless options.include? :more
|
41
|
+
filter = options.select {|opt| opt.kind_of? Regexp}.first
|
42
|
+
methods = methods.select {|name| name =~ filter} if filter
|
43
|
+
|
44
|
+
data = methods.sort.collect do |name|
|
45
|
+
method = obj.method(name)
|
46
|
+
if method.arity == 0
|
47
|
+
args = "()"
|
48
|
+
elsif method.arity > 0
|
49
|
+
n = method.arity
|
50
|
+
args = "(#{(1..n).collect {|i| "arg#{i}"}.join(", ")})"
|
51
|
+
elsif method.arity < 0
|
52
|
+
n = -method.arity
|
53
|
+
args = "(#{(1..n).collect {|i| "arg#{i}"}.join(", ")}, ...)"
|
54
|
+
end
|
55
|
+
klass = $1 if method.inspect =~ /Method: (.*?)#/
|
56
|
+
[name, args, klass]
|
57
|
+
end
|
58
|
+
max_name = data.collect {|item| item[0].size}.max
|
59
|
+
max_args = data.collect {|item| item[1].size}.max
|
60
|
+
data.each do |item|
|
61
|
+
print " #{ANSI_BOLD}#{item[0].rjust(max_name)}#{ANSI_RESET}"
|
62
|
+
print "#{ANSI_GRAY}#{item[1].ljust(max_args)}#{ANSI_RESET}"
|
63
|
+
print " #{ANSI_LGRAY}#{item[2]}#{ANSI_RESET}\n"
|
64
|
+
end
|
65
|
+
data.size
|
66
|
+
end
|
67
|
+
|
68
|
+
# To enable history saving between sessions
|
69
|
+
IRB.conf[:SAVE_HISTORY] = 100
|
70
|
+
|
71
|
+
# Stian Haklev / Joel VanderWerf
|
72
|
+
# To reduce lengthy output
|
73
|
+
class IRB::Context
|
74
|
+
attr_accessor :max_output_size
|
75
|
+
|
76
|
+
alias initialize_before_max_output_size initialize
|
77
|
+
def initialize(*args)
|
78
|
+
initialize_before_max_output_size(*args)
|
79
|
+
@max_output_size = IRB.conf[:MAX_OUTPUT_SIZE] || 70
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class IRB::Irb
|
84
|
+
def output_value
|
85
|
+
text =
|
86
|
+
if @context.inspect?
|
87
|
+
sprintf @context.return_format, @context.last_value.inspect
|
88
|
+
else
|
89
|
+
sprintf @context.return_format, @context.last_value
|
90
|
+
end
|
91
|
+
max = @context.max_output_size
|
92
|
+
if text.size < max
|
93
|
+
puts text
|
94
|
+
else
|
95
|
+
puts text[0..max-1] + "..." + text[-2..-1]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/lib/svmlab-optim.rb
ADDED
@@ -0,0 +1,556 @@
|
|
1
|
+
|
2
|
+
#########################################################################################
|
3
|
+
# OPTIMIZATION METHODS
|
4
|
+
#########################################################################################
|
5
|
+
|
6
|
+
|
7
|
+
class SVMLab
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
# --- updateConfig! ---
|
12
|
+
# This is the interface between an array of variables
|
13
|
+
# to be changed and a configuration hash.
|
14
|
+
# It is to be used by the pattern search, but this
|
15
|
+
# function knows nothing about pattern search. It is
|
16
|
+
# merely an interface between the hash and the
|
17
|
+
# array describing a point in the search space.
|
18
|
+
# cfg: A hash containing what should be updated.
|
19
|
+
# update: An array of paths to what should be updated
|
20
|
+
# and the new value.
|
21
|
+
# output: The cfg hash with updated values.
|
22
|
+
#
|
23
|
+
# EXAMPLE (yaml representation):
|
24
|
+
# cfg =
|
25
|
+
# ---
|
26
|
+
# a:
|
27
|
+
# a: 0
|
28
|
+
# b: 1
|
29
|
+
# b: 2
|
30
|
+
# update =
|
31
|
+
# ---
|
32
|
+
# - "a : b : 7 : exp1"
|
33
|
+
# - "b : 8 : exp1"
|
34
|
+
def updateConfig!(cfg, steps)
|
35
|
+
# For each variable to be updated
|
36
|
+
steps.each do |upd|
|
37
|
+
# Split the path into its levels
|
38
|
+
path = upd.split(/\s\:\s/)
|
39
|
+
# Check if the current value should be an integer
|
40
|
+
path[-2] = if (p=path[-2]) =~ /^\d+$/ then p.to_i
|
41
|
+
elsif p =~ /^\d+\.\d+$/ then p.to_f
|
42
|
+
else p end
|
43
|
+
# Go through the path and update the hash's value
|
44
|
+
(0...path.size-2).inject(cfg) { |c,k|
|
45
|
+
# If this key matches an integer, assume it's an integer
|
46
|
+
if path[k] =~ /^\d+$/ then path[k] = path[k].to_i end
|
47
|
+
if k == path.size-3
|
48
|
+
c[path[k]] = path[-2]
|
49
|
+
else
|
50
|
+
c[path[k]]
|
51
|
+
end
|
52
|
+
}
|
53
|
+
end
|
54
|
+
cfg
|
55
|
+
end
|
56
|
+
|
57
|
+
def scrambleArray(arr)
|
58
|
+
b = []
|
59
|
+
a = arr.clone
|
60
|
+
while a.size > 0
|
61
|
+
b << a.delete_at(rand(a.size))
|
62
|
+
end
|
63
|
+
b
|
64
|
+
end
|
65
|
+
|
66
|
+
# --- getPSsteps ---
|
67
|
+
def getPSsteps(cfg)
|
68
|
+
array = []
|
69
|
+
#1. Walk through cfg[Feature][Features] and look for scalings
|
70
|
+
cfg['Feature']['Features'].each do |feature|
|
71
|
+
if sc = cfg['SVM']['Scale'][feature]
|
72
|
+
sc.inject(0) do |i,sci|
|
73
|
+
if sci.is_a? String
|
74
|
+
sciarr = sci.split
|
75
|
+
if sciarr.size==3 and sciarr[1] =~ /step/
|
76
|
+
array.push('SVM : Scale : '+feature+' : '+i.to_s+' : '+sciarr[0]+' : '+sciarr[2])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
i+=1
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
array = scrambleArray(array)
|
84
|
+
#2. Check SVM parameters
|
85
|
+
if c = cfg['SVM']['C'] and c.is_a? String
|
86
|
+
if (carr = c.split).size ==3 and carr[1] =~ /step/
|
87
|
+
array.push('SVM : C : '+carr[0]+' : '+carr[2])
|
88
|
+
end
|
89
|
+
end
|
90
|
+
if c = cfg['SVM']['e'] and c.is_a? String
|
91
|
+
if (carr = c.split).size ==3 and carr[1] =~ /step/
|
92
|
+
array.push('SVM : e : '+carr[0]+' : '+carr[2])
|
93
|
+
end
|
94
|
+
end
|
95
|
+
if c = cfg['SVM']['g'] and c.is_a? String
|
96
|
+
if (carr = c.split).size ==3 and carr[1] =~ /step/
|
97
|
+
array.push('SVM : g : '+carr[0]+' : '+carr[2])
|
98
|
+
end
|
99
|
+
end
|
100
|
+
if array.size>0 then array else nil end
|
101
|
+
end
|
102
|
+
|
103
|
+
# --- makeUpdate ---
|
104
|
+
# Creates the update array required by 'updateConfig!'.
|
105
|
+
# steps : Array of strings.
|
106
|
+
# Each string :
|
107
|
+
# <lvl 1> : <lvl 2> : ... : <lvl n> : <val> : <X / expX>
|
108
|
+
# movearr : Array of step sizes corresponding to the steps array.
|
109
|
+
# E.g. movearr = [1, 0] means change the first element
|
110
|
+
# of the steps array as curval + 1 * stepsize and leave
|
111
|
+
# the second element unchanged.
|
112
|
+
# Returns a steps array.
|
113
|
+
def makeUpdate(steps,movearr = nil)
|
114
|
+
movearr = Array.new(step.size,0) if !movearr
|
115
|
+
steps.zip(movearr).map { |pm|
|
116
|
+
tmparr = pm[0].split(/\s\:\s/)
|
117
|
+
tmparr[0...-2].join(' : ') + ' : ' + # 1. All leading fields
|
118
|
+
if (num = if tmparr[-1] =~ /^exp\d/ # 2. The value
|
119
|
+
(tmparr[-2].to_f * 10 ** (tmparr[-1].sub(/exp/,'').to_f * pm[1])).to_s
|
120
|
+
elsif tmparr[-1] =~ /^\d$/
|
121
|
+
(tmparr[-2].to_f + tmparr[-1].to_f * pm[1]).to_s
|
122
|
+
end) =~ /\.0$/
|
123
|
+
then num.to_i.to_s
|
124
|
+
else num end + ' : ' +
|
125
|
+
tmparr.last # 3. The step size
|
126
|
+
}
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
# --- patternsearch ---
|
131
|
+
# Should possible be named 'coordinatesearch' since that is
|
132
|
+
# the algorithm that is implemented.
|
133
|
+
def patternsearch(cfg, x, verbose = nil)
|
134
|
+
if verbose
|
135
|
+
line = '#'+Array.new(60,'-').join
|
136
|
+
halfline = '#'+Array.new(43,'-').join
|
137
|
+
puts line,'#PATTERN SEARCH INITIAL POINT',{'init'=> x}.to_yaml,line
|
138
|
+
end
|
139
|
+
xn = x.size
|
140
|
+
s = Array.new(xn,0)
|
141
|
+
updateConfig!(cfg, makeUpdate(x,s))
|
142
|
+
delta = 1.0
|
143
|
+
iteration = 0
|
144
|
+
pred = SVMLab.new(cfg).crossvalidate
|
145
|
+
bestpred = pred
|
146
|
+
m = pred.rmsd
|
147
|
+
@pslog = [ {'time' => Time.now,
|
148
|
+
'rmsd' => m,
|
149
|
+
'cc' => bestpred.cc,
|
150
|
+
'delta' => delta,
|
151
|
+
'x' => x.dup,
|
152
|
+
'cfg' => deepcopy(cfg)} ]
|
153
|
+
outputtitle =
|
154
|
+
(['Iter','Delta'] +
|
155
|
+
x.map{|xi|
|
156
|
+
arr = xi.split(' : ')
|
157
|
+
arr[arr.size>4 ? -4 : -3]} +
|
158
|
+
['RMSD','CC']).join("\t")
|
159
|
+
outputline =
|
160
|
+
([iteration, '-'] +
|
161
|
+
x.map{|xi| "%.2f"%(xi.split(':')[-2].to_f)} +
|
162
|
+
["%.2f"%m, "%.2f"%bestpred.cc]).join("\t")
|
163
|
+
puts "PATTERN SEARCH"
|
164
|
+
puts outputtitle,outputline
|
165
|
+
if verbose
|
166
|
+
puts "#INITIAL VALUE : %.3f"%m + " (cc %.3f)"%pred.cc, line
|
167
|
+
puts halfline, "#\t\t\tDELTA -> " + delta.to_s, halfline
|
168
|
+
puts ( {'errors' => [m]}.to_yaml[5..-1] )
|
169
|
+
end
|
170
|
+
nhalf = 0
|
171
|
+
while nhalf <= cfg['SVM']['Optimization']['Nhalf'] do
|
172
|
+
s = Array.new(xn,0)
|
173
|
+
(0...xn).each do |i|
|
174
|
+
ei = Array.new(xn,0); ei[i] = 1
|
175
|
+
[-1,1].each do |d|
|
176
|
+
si = s.zip(ei).map { |se| se[0] + delta * d * se[1] }
|
177
|
+
updateConfig!(cfg, makeUpdate(x,si))
|
178
|
+
pred = SVMLab.new(cfg.to_yaml).crossvalidate
|
179
|
+
val = pred.rmsd
|
180
|
+
#val = 1 - pred.cc # Try CC as measure instead
|
181
|
+
if m - m*10**-5 > val
|
182
|
+
s = si.dup
|
183
|
+
m = val
|
184
|
+
bestpred = pred
|
185
|
+
puts '#' + x[i].gsub("\s",'').split(/\:/)[0...-1].join(':') +
|
186
|
+
' -> ' + si[i].to_s +
|
187
|
+
"\tRMSD -> %.3f"%val +
|
188
|
+
"\t(cc %.3f)"%pred.cc if verbose
|
189
|
+
break
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
olddelta = delta
|
194
|
+
if s.detect{|ss| ss != 0}
|
195
|
+
updateConfig!(cfg, x = makeUpdate(x,s) )
|
196
|
+
else
|
197
|
+
delta = delta / 2
|
198
|
+
nhalf += 1
|
199
|
+
if verbose
|
200
|
+
puts "#\t\t\tDELTA -> " + delta.to_s
|
201
|
+
puts "- #{m}" if nhalf <= cfg['SVM']['Optimization']['Nhalf']
|
202
|
+
end
|
203
|
+
updateConfig!(cfg, x)
|
204
|
+
end
|
205
|
+
iteration += 1
|
206
|
+
outputline =
|
207
|
+
([iteration, olddelta] +
|
208
|
+
x.map{|xi| "%.2f"%(xi.split(':')[-2].to_f)} +
|
209
|
+
["%.2f"%bestpred.rmsd, "%.2f"%bestpred.cc]).join("\t")
|
210
|
+
puts outputline
|
211
|
+
puts halfline if verbose
|
212
|
+
@pslog.push( { 'time' => Time.now,
|
213
|
+
'rmsd' => bestpred.rmsd,
|
214
|
+
'cc' => bestpred.cc,
|
215
|
+
'delta' => delta,
|
216
|
+
'x' => x.dup,
|
217
|
+
'cfg' => deepcopy(cfg) } )
|
218
|
+
end
|
219
|
+
if verbose
|
220
|
+
puts line,'#'+Time.now.to_s + ' PATTERN SEARCH FINAL ERROR ' + m.to_s
|
221
|
+
puts ( {'finalerr' => m}.to_yaml[5..-1] )
|
222
|
+
puts line,'#PATTERN SEARCH FINAL POINT',{'final'=>x}.to_yaml[5..-1],line
|
223
|
+
puts ( {'endtime' => Time.now.to_s}.to_yaml[5..-1] )
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
|
228
|
+
# --- quasiNewton ---
|
229
|
+
def quasiNewton(cfg, x, verbose = nil)
|
230
|
+
delta = 1.0
|
231
|
+
nhalved = 0
|
232
|
+
s = Array.new(x.size,0)
|
233
|
+
loop do
|
234
|
+
# Calculate the center value
|
235
|
+
updateConfig!(cfg, x = makeUpdate(x,s))
|
236
|
+
centerval = SVMLab.new(cfg.to_yaml).crossvalidate.rmsd
|
237
|
+
# Calculate values around the current point
|
238
|
+
puts '***',"%.3f"%centerval,'***' if verbose
|
239
|
+
val = (0...x.size).map { |i|
|
240
|
+
ei=Array.new(x.size,0); ei[i] = 1
|
241
|
+
[-1,1].map { |d|
|
242
|
+
si = ei.map { |se| delta * d * se }
|
243
|
+
updateConfig!(cfg, makeUpdate(x,si))
|
244
|
+
v = SVMLab.new(cfg.to_yaml).crossvalidate.rmsd
|
245
|
+
#puts "If #{x[i]} is #{si[i]} then rmsd = #{v}"
|
246
|
+
v
|
247
|
+
} }
|
248
|
+
|
249
|
+
s = Array.new(x.size,0)
|
250
|
+
|
251
|
+
case cfg['SVM']['Optimization']['StepMethod']
|
252
|
+
|
253
|
+
when 'Gradient'
|
254
|
+
# Calculate gradient and gradient norm
|
255
|
+
gradient = val.map{ |valx|
|
256
|
+
mini = valx[0]<valx[1] ? 0 : 1
|
257
|
+
if valx[mini] < centerval
|
258
|
+
(centerval - valx[mini]) * (mini==0 ? 1 : -1)
|
259
|
+
else 0.0 end }
|
260
|
+
gradnorm = Math.sqrt(gradient.inject(0) { |sqsum,gi| sqsum += gi**2 })
|
261
|
+
delta = delta / 2 if gradnorm < 0.01
|
262
|
+
normedgrad = gradient.map{|gi| gi / gradnorm}
|
263
|
+
s = normedgrad.map{|gi| -gi * delta} # Negative gradient direction
|
264
|
+
if verbose
|
265
|
+
puts "Grad: |#{"%.3f"%gradnorm}| : #{gradient.map{|g| "%.2f"%g}.join(' ')}"
|
266
|
+
end
|
267
|
+
|
268
|
+
when 'MaxDescentAxis'
|
269
|
+
# Calculate the axis and direction that gives max descent
|
270
|
+
daxis = (0...val.size).zip(val).sort{|a,b| a[1]<=>b[1]}.first[0]
|
271
|
+
ddir = val[daxis][0] < val[daxis][1] ? 0 : 1
|
272
|
+
if val[daxis][ddir] < centerval
|
273
|
+
s[daxis] = (ddir==0?-1:1) * delta
|
274
|
+
if verbose then puts "Changing #{daxis} to #{s[daxis]} " +
|
275
|
+
"since it gives #{"%.3f"%val[daxis][ddir]}\n #{x[daxis]}"
|
276
|
+
end
|
277
|
+
else
|
278
|
+
delta = delta / 2
|
279
|
+
nhalved += 1
|
280
|
+
puts "Halving step size to #{delta}" if verbose
|
281
|
+
end
|
282
|
+
break if nhalved > cfg['SVM']['Optimization']['Nhalf']
|
283
|
+
end
|
284
|
+
#if verbose
|
285
|
+
# puts 'S: ' + s.map{|si| si.is_a? Fixnum ? si.to_s : "%.2f"%si}.join(' ')
|
286
|
+
#end
|
287
|
+
end
|
288
|
+
updateConfig!(cfg, x)
|
289
|
+
end
|
290
|
+
|
291
|
+
def checkOptimization(cfg)
|
292
|
+
if x = getPSsteps(cfg)
|
293
|
+
#puts x
|
294
|
+
if cfg['SVM']['Optimization'] and
|
295
|
+
(method = cfg['SVM']['Optimization']['Method'])
|
296
|
+
#puts '---',method,'---'
|
297
|
+
eval("#{method}(cfg, x, nil)")
|
298
|
+
# Currently implemented methods:
|
299
|
+
# patternsearch(cfg, x)
|
300
|
+
# quasiNewton(cfg, x)
|
301
|
+
else
|
302
|
+
raise "Scale optimization requested in config but " +
|
303
|
+
"no optimization method given."
|
304
|
+
end
|
305
|
+
else
|
306
|
+
cfg
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
def deepcopy(obj)
|
311
|
+
Marshal::load(Marshal::dump(obj))
|
312
|
+
end
|
313
|
+
|
314
|
+
# # ----------------------Old code from here----------------------------
|
315
|
+
#
|
316
|
+
#
|
317
|
+
# def patternsearch_fredrik(steps, psreport = '/tmp/ps', errormeasure = 'RMSD')
|
318
|
+
# stephalved = 0
|
319
|
+
# bestcfg = nil
|
320
|
+
# nstep = 0
|
321
|
+
# linesep = '**************'
|
322
|
+
# open(psreport,'w') { |f| f.puts linesep,'PATTERN SEARCH',Time.now,linesep }
|
323
|
+
# while stephalved<2 do
|
324
|
+
# open(psreport,'a') { |f| f.puts linesep, "STEP #{nstep+=1}, " + Time.now.to_s, steps }
|
325
|
+
# pattern = getpattern(@cfg, steps)
|
326
|
+
# bestcfg = YAML.load(pattern[0]) if !bestcfg
|
327
|
+
# pindex = -1
|
328
|
+
# maxparallel = 7
|
329
|
+
# parallel = 0
|
330
|
+
# pattern.each do |p|
|
331
|
+
# rfile = "/tmp/patternsearch#{pindex+=1}.yml"
|
332
|
+
# open("/tmp/pattern#{pindex}.yml","w"){|f| f.puts p}
|
333
|
+
# if parallel >= maxparallel
|
334
|
+
# Process.wait
|
335
|
+
# parallel -= 1
|
336
|
+
# end
|
337
|
+
# fork do
|
338
|
+
# lab = SVMLab.new(p)
|
339
|
+
# err, predictions = lab.publish_crossvalidate(rfile)
|
340
|
+
# end
|
341
|
+
# parallel += 1
|
342
|
+
# end
|
343
|
+
# Process.waitall
|
344
|
+
# evaluation = {}
|
345
|
+
# (0...pattern.size).each do |pindex|
|
346
|
+
# rfile = File.new("/tmp/patternsearch#{pindex}.yml")
|
347
|
+
# evaluation[pindex] = YAML.load(rfile)['Evaluation'][errormeasure]
|
348
|
+
# end
|
349
|
+
# # Calculate gradient
|
350
|
+
# gradient = (1..(pattern.size-1)/2).map { |dim|
|
351
|
+
# evaluation[2*dim].to_f - evaluation[2*dim-1].to_f }
|
352
|
+
# gradnorm = Math.sqrt(gradient.inject(0) { |sqsum,dim| sqsum += dim**2 })
|
353
|
+
# open(psreport,'a') { |f| f.puts "Gradient" +
|
354
|
+
# gradient.inject(''){|str,d| str+=" %.2f"%d} + " (%.2f)"%gradnorm }
|
355
|
+
# # Find minimum error configuration
|
356
|
+
# mincfg = evaluation.sort{|alfa,beta| alfa[1]<=>beta[1]}.first
|
357
|
+
# bestcfg = YAML.load( pattern[mincfg[0]] )
|
358
|
+
# open(psreport,'a') { |f| f.puts 'Error ' + evaluation[0].to_s }
|
359
|
+
# # Update steps
|
360
|
+
# if (mincfg[1] - evaluation[0]).abs < 1e-4
|
361
|
+
# open(psreport,'a') { |f| f.puts linesep,'HALVING' }
|
362
|
+
# steps.collect! do |step|
|
363
|
+
# if step=~/exp\d+/
|
364
|
+
# prefix = if step=~/int/ then 'intexp' else 'exp' end
|
365
|
+
# (step.split(/\s\:\s/)[0...-1] + [prefix+(step.split(/exp/).last.to_f/2).to_s]).join(' : ')
|
366
|
+
# else
|
367
|
+
# (step.split(/\s\:\s/)[0...-1] + [(step.split(/\s\:\s/).last.to_f/2).to_s]).join(' : ')
|
368
|
+
# end
|
369
|
+
# end
|
370
|
+
# stephalved += 1
|
371
|
+
# else
|
372
|
+
# open(psreport,'a') { |f| f.puts linesep,'MOVING ' }
|
373
|
+
# steps.collect! do |step|
|
374
|
+
# path = step.split(/\s\:\s/)
|
375
|
+
# tmpcfg = bestcfg
|
376
|
+
# path[0...-3].each do |pathpart|
|
377
|
+
# tmpcfg = tmpcfg[pathpart]
|
378
|
+
# end
|
379
|
+
# (path[0...-2] +
|
380
|
+
# [tmpcfg[ if path[-3]=~/^\d+$/ then path[-3].to_i
|
381
|
+
# else path[-3] end ].to_s ] +
|
382
|
+
# [path.last]).join(' : ')
|
383
|
+
# end
|
384
|
+
# # Gradient descent
|
385
|
+
# #gradindex = -1
|
386
|
+
# #steps.collect! do |step|
|
387
|
+
# # path = step.split(/\s\:\s/)
|
388
|
+
# # tmpcfg = bestcfg
|
389
|
+
# # path[0...-3].each do |pathpart|
|
390
|
+
# # tmpcfg = tmpcfg[pathpart]
|
391
|
+
# # end
|
392
|
+
# # (path[0...-2] +
|
393
|
+
# # [ if path[-1] =~ /exp/
|
394
|
+
# # path[-2].to_f * 10**(-path[-1].sub(/exp/,'').to_f * gradient[gradindex+=1] / gradnorm)
|
395
|
+
# # else
|
396
|
+
# # path[-2].to_f + (tmpcfg[path[-3]].to_f - path[-2].to_f).abs * gradient[gradindex+=1] / gradnorm
|
397
|
+
# # end.to_s ] +
|
398
|
+
# # [path.last]).join(' : ')
|
399
|
+
# #end
|
400
|
+
# end
|
401
|
+
# end
|
402
|
+
# open(psreport,'a') { |f| f.puts linesep,Time.now,'FINAL STEPS',steps,linesep }
|
403
|
+
# bestcfg
|
404
|
+
# end
|
405
|
+
#
|
406
|
+
# # --- getpattern ---
|
407
|
+
# # structure : A hash consisting the configuration. The leaves in the
|
408
|
+
# # hash are ignored and only the structure is utilized.
|
409
|
+
# # steps : An array of strings in which each string describes the
|
410
|
+
# # path in the "structure" hash to the parameter:
|
411
|
+
# # <Level1> : <Level2> : ... : <Parameter> : <CurValue> : <Stepsize>
|
412
|
+
# # "CurValue" is the value from which to create the pattern
|
413
|
+
# # "Stepsize" is a string :
|
414
|
+
# # <x>, exp<x> or intexp<x> where x is a Float or Fixnum
|
415
|
+
# # returns : an array of strings in which each string is the YAML
|
416
|
+
# # representation of the configuration.
|
417
|
+
# # The current point given by "CurValue" is returned as
|
418
|
+
# # the first element in the array.
|
419
|
+
# def getpattern(structure, steps)
|
420
|
+
# pattern = []
|
421
|
+
# (['dontmove'] + steps).each do |step1|
|
422
|
+
# if step1=='dontmove' then [0] else [-1,1] end.each do |factor|
|
423
|
+
# steparr = []
|
424
|
+
# steps.each do |step2|
|
425
|
+
# s2 = step2.split(/\s\:\s/)
|
426
|
+
# if step1==step2
|
427
|
+
# # This step will be changed according to factor and stepsize
|
428
|
+
# ss = if s2[-1] =~ /exp/
|
429
|
+
# ss = s2[-2].to_f * 10**(s2[-1].split(/exp/).last.to_f * factor)
|
430
|
+
# if s2[-1] =~ /int/ then ss.round else ss end
|
431
|
+
# else
|
432
|
+
# ss = s2[-2].to_f + s2[-1].to_f * factor
|
433
|
+
# if ss.to_s =~ /\.0$/ then ss.to_i else ss end
|
434
|
+
# end
|
435
|
+
# steparr.push( s2[0...-2].join(':') + ' ' + ss.to_s )
|
436
|
+
# else
|
437
|
+
# # Put the current point in steparr
|
438
|
+
# steparr.push( s2[0...-2].join(':') + ' ' + s2[-2] )
|
439
|
+
# end
|
440
|
+
# end
|
441
|
+
# # Generate config text for each step
|
442
|
+
# cfg = deepcopy(structure) # Do not change the argument given
|
443
|
+
# steparr.each do |step|
|
444
|
+
# intcfg = cfg
|
445
|
+
# path,val = step.split
|
446
|
+
# val = if val=~ /\.0$/ then val.to_i else val.to_f end
|
447
|
+
# path.split(/\:/)[0...-1].each do |p|
|
448
|
+
# intcfg = intcfg[p]
|
449
|
+
# end
|
450
|
+
# intcfg[ if (index = path.split(/\:/).last) =~ /^\d+$/
|
451
|
+
# then index.to_i
|
452
|
+
# else index end ] = val
|
453
|
+
# end
|
454
|
+
# pattern.push( cfg.to_yaml )
|
455
|
+
# end
|
456
|
+
# end
|
457
|
+
# pattern
|
458
|
+
# end
|
459
|
+
#
|
460
|
+
#
|
461
|
+
# #########################################################################################
|
462
|
+
# # Grid search - possibly obsolete
|
463
|
+
#
|
464
|
+
# # --- loo_svmoptim_gridsearch ---
|
465
|
+
# # Performs a grid search of the SVM hyperparameter space, i.e. does
|
466
|
+
# # a cross validation using different values of C, epsilon and gamma
|
467
|
+
# # (assuming we are doing epsilon regression with an RBF kernel)
|
468
|
+
# def loo_svmoptim_gridsearch()
|
469
|
+
# err, predictions = looCrossvalidate
|
470
|
+
# print 'Default: epsilon '+@par.eps.to_s
|
471
|
+
# print "\tgamma "+@par.gamma.to_s
|
472
|
+
# print "\tC "+@par.C.to_s
|
473
|
+
# print "\tError %.3f"%err
|
474
|
+
# puts
|
475
|
+
#
|
476
|
+
# epsilon = -3..0
|
477
|
+
# gamma = -2..1
|
478
|
+
# cee = -1..2
|
479
|
+
# optimum = {}
|
480
|
+
# epsilon.each { |e|
|
481
|
+
# @par.eps = 10**e
|
482
|
+
# gamma.each { |g|
|
483
|
+
# @par.gamma = 10**g
|
484
|
+
# cee.each {|c|
|
485
|
+
# @par.C = 10**c
|
486
|
+
# err,predictions = looCrossvalidate
|
487
|
+
# print 'epsilon '+@par.eps.to_s
|
488
|
+
# print "\tgamma "+@par.gamma.to_s
|
489
|
+
# print "\tC "+@par.C.to_s
|
490
|
+
# print "\tError %.3f"%err
|
491
|
+
# if !optimum['err'] or optimum['err'] > err
|
492
|
+
# optimum['err'] = err
|
493
|
+
# optimum['epsilon'] = 10**e
|
494
|
+
# optimum['gamma'] = 10**g
|
495
|
+
# optimum['C'] = 10**c
|
496
|
+
# end
|
497
|
+
# print "\tOptimum %.3f"%optimum['err'] if optimum['err']
|
498
|
+
# puts
|
499
|
+
# }
|
500
|
+
# }
|
501
|
+
# }
|
502
|
+
# @par.eps = optimum['epsilon']
|
503
|
+
# @par.gamma = optimum['gamma']
|
504
|
+
# @par.C = optimum['C']
|
505
|
+
# optimum.each{ |key,val|
|
506
|
+
# puts key + ' = ' + val.to_s
|
507
|
+
# }
|
508
|
+
# end
|
509
|
+
#
|
510
|
+
# # --- svmoptim_gridsearch ---
|
511
|
+
# # Performs a grid search of the SVM hyperparameter space, i.e. does
|
512
|
+
# # a cross validation using different values of C, epsilon and gamma
|
513
|
+
# # (assuming we are doing epsilon regression with an RBF kernel)
|
514
|
+
# def svmoptim_gridsearch(groups)
|
515
|
+
# err, predictions = crossvalidate(groups)
|
516
|
+
# print 'Default: epsilon '+@par.eps.to_s
|
517
|
+
# print "\tgamma "+@par.gamma.to_s
|
518
|
+
# print "\tC "+@par.C.to_s
|
519
|
+
# print "\tError %.3f"%err
|
520
|
+
# puts
|
521
|
+
#
|
522
|
+
# epsilon = -3..0
|
523
|
+
# gamma = -2..1
|
524
|
+
# cee = -1..2
|
525
|
+
# optimum = {}
|
526
|
+
# epsilon.each { |e|
|
527
|
+
# @par.eps = 10**e
|
528
|
+
# gamma.each { |g|
|
529
|
+
# @par.gamma = 10**g
|
530
|
+
# cee.each {|c|
|
531
|
+
# @par.C = 10**c
|
532
|
+
# err,predictions = crossvalidate(groups)
|
533
|
+
# print 'epsilon '+@par.eps.to_s
|
534
|
+
# print "\tgamma "+@par.gamma.to_s
|
535
|
+
# print "\tC "+@par.C.to_s
|
536
|
+
# print "\tError %.3f"%err
|
537
|
+
# if !optimum['err'] or optimum['err'] > err
|
538
|
+
# optimum['err'] = err
|
539
|
+
# optimum['epsilon'] = 10**e
|
540
|
+
# optimum['gamma'] = 10**g
|
541
|
+
# optimum['C'] = 10**c
|
542
|
+
# end
|
543
|
+
# print "\tOptimum %.3f"%optimum['err'] if optimum['err']
|
544
|
+
# puts
|
545
|
+
# }
|
546
|
+
# }
|
547
|
+
# }
|
548
|
+
# @par.eps = optimum['epsilon']
|
549
|
+
# @par.gamma = optimum['gamma']
|
550
|
+
# @par.C = optimum['C']
|
551
|
+
# optimum.each{ |key,val|
|
552
|
+
# puts key + ' = ' + val.to_s
|
553
|
+
# }
|
554
|
+
# end
|
555
|
+
|
556
|
+
end
|