载入与保存
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出现。
欢迎参与讨论并关注本博客和微博以及知乎个人主页后续内容继续更新哦~
转载请您尊重作者的劳动,完整保留上述文字以及文章链接,谢谢您的支持!