您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān)Keras中循環(huán)使用K.ctc_decode內(nèi)存不釋放怎么辦,小編覺得挺實(shí)用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
如下一段代碼,在多次調(diào)用了K.ctc_decode時,會發(fā)現(xiàn)程序占用的內(nèi)存會越來越高,執(zhí)行速度越來越慢。
data = generator(...) model = init_model(...) for i in range(NUM): x, y = next(data) _y = model.predict(x) shape = _y.shape input_length = np.ones(shape[0]) * shape[1] ctc_decode = K.ctc_decode(_y, input_length)[0][0] out = K.get_value(ctc_decode)
原因
每次執(zhí)行ctc_decode時都會向計算圖中添加一個節(jié)點(diǎn),這樣會導(dǎo)致計算圖逐漸變大,從而影響計算速度和內(nèi)存。
PS:有資料說是由于get_value導(dǎo)致的,其中也給出了解決方案。
但是我將ctc_decode放在循環(huán)體之外就不再出現(xiàn)內(nèi)存和速度問題,這是否說明get_value影響其實(shí)不大呢?
解決方案
通過K.function封裝K.ctc_decode,只需初始化一次,只向計算圖中添加一個計算節(jié)點(diǎn),然后多次調(diào)用該節(jié)點(diǎn)(函數(shù))
data = generator(...) model = init_model(...) x = model.output # [batch_sizes, series_length, classes] input_length = KL.Input(batch_shape=[None], dtype='int32') ctc_decode = K.ctc_decode(x, input_length=input_length * K.shape(x)[1]) decode = K.function([model.input, input_length], [ctc_decode[0][0]]) for i in range(NUM): _x, _y = next(data) out = decode([_x, np.ones(1)])
補(bǔ)充知識:CTC_loss和CTC_decode的模型封裝代碼避免節(jié)點(diǎn)不斷增加
該問題可以參考上面的描述,無論是CTC_decode還是CTC_loss,每次運(yùn)行都會創(chuàng)建節(jié)點(diǎn),避免的方法是將其封裝到model中,這樣就固定了計算節(jié)點(diǎn)。
測試方法: 在初始化節(jié)點(diǎn)后(注意是在運(yùn)行fit/predict至少一次后,因為這些方法也會更改計算圖狀態(tài)),運(yùn)行K.get_session().graph.finalize()鎖定節(jié)點(diǎn),此時如果圖節(jié)點(diǎn)變了會報錯并提示出錯代碼。
from keras import backend as K from keras.layers import Lambda,Input from keras import Model from tensorflow.python.ops import ctc_ops as ctc import tensorflow as tf from keras.layers import Layer class CTC_Batch_Cost(): ''' 用于計算CTC loss ''' def ctc_lambda_func(self,args): """Runs CTC loss algorithm on each batch element. # Arguments y_true: tensor `(samples, max_string_length)` 真實(shí)標(biāo)簽 y_pred: tensor `(samples, time_steps, num_categories)` 預(yù)測前未經(jīng)過softmax的向量 input_length: tensor `(samples, 1)` 每一個y_pred的長度 label_length: tensor `(samples, 1)` 每一個y_true的長度 # Returns Tensor with shape (samples,1) 包含了每一個樣本的ctc loss """ y_true, y_pred, input_length, label_length = args # y_pred = y_pred[:, :, :] # y_pred = y_pred[:, 2:, :] return self.ctc_batch_cost(y_true, y_pred, input_length, label_length) def __call__(self, args): ''' ctc_decode 每次創(chuàng)建會生成一個節(jié)點(diǎn),這里參考了上面的內(nèi)容 將ctc封裝成模型,是否會解決這個問題還沒有測試過這種方法是否還會出現(xiàn)創(chuàng)建節(jié)點(diǎn)的問題 ''' y_true = Input(shape=(None,)) y_pred = Input(shape=(None,None)) input_length = Input(shape=(1,)) label_length = Input(shape=(1,)) lamd = Lambda(self.ctc_lambda_func, output_shape=(1,), name='ctc')([y_true,y_pred,input_length,label_length]) model = Model([y_true,y_pred,input_length,label_length],[lamd],name="ctc") # return Lambda(self.ctc_lambda_func, output_shape=(1,), name='ctc')(args) return model(args) def ctc_batch_cost(self,y_true, y_pred, input_length, label_length): """Runs CTC loss algorithm on each batch element. # Arguments y_true: tensor `(samples, max_string_length)` containing the truth labels. y_pred: tensor `(samples, time_steps, num_categories)` containing the prediction, or output of the softmax. input_length: tensor `(samples, 1)` containing the sequence length for each batch item in `y_pred`. label_length: tensor `(samples, 1)` containing the sequence length for each batch item in `y_true`. # Returns Tensor with shape (samples,1) containing the CTC loss of each element. """ label_length = tf.to_int32(tf.squeeze(label_length, axis=-1)) input_length = tf.to_int32(tf.squeeze(input_length, axis=-1)) sparse_labels = tf.to_int32(K.ctc_label_dense_to_sparse(y_true, label_length)) y_pred = tf.log(tf.transpose(y_pred, perm=[1, 0, 2]) + 1e-7) # 注意這里的True是為了忽略解碼失敗的情況,此時loss會變成nan直到下一個個batch return tf.expand_dims(ctc.ctc_loss(inputs=y_pred, labels=sparse_labels, sequence_length=input_length, ignore_longer_outputs_than_inputs=True), 1) # 使用方法:(注意shape) loss_out = CTC_Batch_Cost()([y_true, y_pred, audio_length, label_length])
from keras import backend as K from keras.layers import Lambda,Input from keras import Model from tensorflow.python.ops import ctc_ops as ctc import tensorflow as tf from keras.layers import Layer class CTCDecodeLayer(Layer): def __init__(self, **kwargs): super().__init__(**kwargs) def _ctc_decode(self,args): base_pred, in_len = args in_len = K.squeeze(in_len,axis=-1) r = K.ctc_decode(base_pred, in_len, greedy=True, beam_width=100, top_paths=1) r1 = r[0][0] prob = r[1][0] return [r1,prob] def call(self, inputs, **kwargs): return self._ctc_decode(inputs) def compute_output_shape(self, input_shape): return [(None,None),(1,)] class CTCDecode(): '''用與CTC 解碼,得到真實(shí)語音序列 2019年7月18日所寫,對ctc_decode使用模型進(jìn)行了封裝,從而在初始化完成后不會再有新節(jié)點(diǎn)的產(chǎn)生 ''' def __init__(self): base_pred = Input(shape=[None,None],name="pred") feature_len = Input(shape=[1,],name="feature_len") r1, prob = CTCDecodeLayer()([base_pred,feature_len]) self.model = Model([base_pred,feature_len],[r1,prob]) pass def ctc_decode(self,base_pred,in_len,return_prob = False): ''' :param base_pred:[sample,timestamp,vector] :param in_len: [sample,1] :return: ''' result,prob = self.model.predict([base_pred,in_len]) if return_prob: return result,prob return result def __call__(self,base_pred,in_len,return_prob = False): return self.ctc_decode(base_pred,in_len,return_prob) # 使用方法:(注意shape,是batch級的輸入) ctc_decoder = CTCDecode() ctc_decoder.ctc_decode(result,feature_len)
關(guān)于Keras中循環(huán)使用K.ctc_decode內(nèi)存不釋放怎么辦就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。