載入與保存
Python標準的保存類別實體並重新載入它們的途徑是pickle機制。許多Theano對象可以由此被序列化(或者反序列化),然而pickle的侷限性在於,被序列化的類別實例的代碼或者數據並沒有被同時保存。因此重新載入先前版本的類可能會出問題。
因此,需要尋求基於預期保存和重新載入的耗時的不同機制。
對於短期(比如臨時文件和網絡轉錄),Theano的pickle是可行的。
對於長期(比如從實驗中保存模型)不應當依賴於Theano的pickle對象。
推薦在任何其他Python項目的過程中的保存和載入底層共享對象。
Pickle基礎
pickle和cPickle模塊功能相似,但是cPickle用C編碼,要更快一些。
可以用cPickle.dump把對象序列化(或者保存或者pickle)爲一個文件。
importcPickle
f= file('obj.save', 'wb')
cPickle.dump(my_obj,f, protocol=cPickle.HIGHEST_PROTOCOL)
f.close()
使用了cPickle.HIGHEST_PROTOCOL,使得保存對象的過程大大加快。
使用了’b’二進制模式,是爲了在Unix和Windows系統之間保持可移植性。
使用cPickle.load把文件反序列化(或載入,或unpickle)
f= file('obj.save', 'rb')
loaded_obj= cPickle.load(f)
f.close()
可以同時pickle多個對象到同一個文件:
f= file('objects.save', 'wb')
forobj in [obj1, obj2, obj3]:
cPickle.dump(obj, f,protocol=cPickle.HIGHEST_PROTOCOL)
f.close()
也可以按照同樣的順序載入:
f= file('objects.save', 'rb')
loaded_objects= []
fori in range(3):
loaded_objects.append(cPickle.load(f))
f.close()
短期序列化
如果有信心,pickle整個模型是個好辦法。
這種情況是指,你在項目中執行同樣的保存和重載操作,或者這個類已經穩定運行很久了。
通過定義__getstate__ method和__setstate__可以控制從項目中保存何種pickle。
如果模型類包含了正在使用數據集的鏈接,而又不想pickle每個模型實例,上述控制方法會很實用。
def__getstate__(self):
state = dict(self.__dict__)
del state['training_set']
return state
def__setstate__(self, d):
self.__dict__.update(d)
self.training_set =cPickle.load(file(self.training_set_file, 'rb'))
長期序列化
如果想要保存的類運行不穩定,例如有函數創建或者刪除、類成員重命名,應該只保存或載入類的不可變部分。
依然是使用定義__getstate__ method和__setstate__
例如只想要保存權重矩陣W和偏倚項b:
def__getstate__(self):
return (self.W, self.b)
def__setstate__(self, state):
W, b = state
self.W = W
self.b = b
如果更新了下列函數來表現變量名稱的改變,那麼即使W和b被重命名爲weights和bias,之前的pickle文件依然是可用的:
def__getstate__(self):
return (self.weights, self.bias)
def__setstate__(self, state):
W, b = state
self.weights = W
self.bias = b
條件
-IfElse與Switch
-switch比ifelse更通用,因爲switch是逐位操作。
-switch把2個輸出變量都計算了,所以比ifelse要慢(只算1個)。
from theano import tensor as T
from theano.ifelse import ifelse
importtheano, time, numpy
a,b= T.scalars('a', 'b')
x,y= T.matrices('x', 'y')
z_switch= T.switch(T.lt(a, b), T.mean(x), T.mean(y))
z_lazy= ifelse(T.lt(a, b), T.mean(x), T.mean(y))
f_switch= theano.function([a, b, x, y], z_switch,
mode=theano.Mode(linker='vm'))
f_lazyifelse= theano.function([a, b, x, y], z_lazy,
mode=theano.Mode(linker='vm'))
val1= 0.
val2= 1.
big_mat1= numpy.ones((10000, 1000))
big_mat2= numpy.ones((10000, 1000))
n_times= 10
tic= time.clock()
fori in xrange(n_times):
f_switch(val1, val2, big_mat1, big_mat2)
print'time spent evaluating both values %f sec' % (time.clock() - tic)
tic= time.clock()
fori in xrange(n_times):
f_lazyifelse(val1, val2, big_mat1,big_mat2)
print'time spent evaluating one value %f sec' % (time.clock() - tic)
測試結果
time spent evaluating both values 0.200000 sec
time spent evaluating one value 0.110000 sec
可見ifelse確實快了1倍,但是必須使用vm或者cvm作爲Linker,而未來cvm會作爲默認Linker出現。
歡迎參與討論並關注本博客和微博以及知乎個人主頁後續內容繼續更新哦~
轉載請您尊重作者的勞動,完整保留上述文字以及文章鏈接,謝謝您的支持!