CTC loss 理解
前言:理解了很久的CTC,每次都是點到即止,所以一直沒有很明確,現在重新整理。
定義
CTC (Connectionist Temporal Classification)是一種loss function
對比
傳統方法
在傳統的語音識別的模型中,我們對語音模型進行訓練之前,往往都要將文字與語音進行嚴格的對齊操作。這樣就有兩點不太好:
1. 嚴格對齊要花費人力、時間。
2. 嚴格對齊之後,模型預測出的label只是區域性分類的結果,而無法給出整個序列的輸出結果,往往要對預測出的label做一些後處理才可以得到我們最終想要的結果。
雖然現在已經有了一些比較成熟的開源對齊工具供大家使用,但是隨著deep learning越來越火,有人就會想,能不能讓我們的網路自己去學習對齊方式呢?因此CTC(Connectionist temporal classification)就應運而生啦。
想一想,為什麼CTC就不需要去對齊語音和文字呢?因為CTC它允許我們的神經網路在任意一個時間段預測label,只有一個要求:就是輸出的序列順序只要是正確的就ok啦~這樣我們就不在需要讓文字和語音嚴格對齊了,而且CTC輸出的是整個序列標籤,因此也不需要我們再去做一些後處理操作。
對一段音訊使用CTC和使用文字對齊的例子如下圖所示:
主要區別
訓練流程和傳統的神經網路類似,構建loss function,然後根據BP演算法進行訓練,不同之處在於傳統的神經網路的訓練準則是針對每幀資料,即每幀資料的訓練誤差最小,而CTC的訓練準則是基於序列(比如語音識別的一整句話)的,比如最大化 ,序列化的概率求解比較複雜,因為一個輸出序列可以對應很多的路徑,所有引入前後向演算法來簡化計算。
演算法細節
符號定義
概率計算
誤差反傳
參考文獻
實現程式碼
#coding=utf-8
import time
import tensorflow as tf
import scipy.io.wavfile as wav
import numpy as np
from six.moves import xrange as range
try:
from python_speech_features import mfcc
except ImportError:
print("Failed to import python_speech_features.\n Try pip install python_speech_features.")
raise ImportError
# 常量
SPACE_TOKEN = '<space>'
SPACE_INDEX = 0
FIRST_INDEX = ord('a') - 1 # 0 is reserved to space
# mfcc預設提取出來的一幀13個特徵
num_features = 13
# 26個英文字母 + 1個空白 + 1個no label = 28 label個數
num_classes = ord('z') - ord('a') + 1 + 1 + 1
# 迭代次數
num_epochs = 200
# lstm隱藏單元數
num_hidden = 40
# 2層lstm網路
num_layers = 1
# batch_size設定為1
batch_size = 1
# 初始學習率
initial_learning_rate = 0.01
# 樣本個數
num_examples = 1
# 一個epoch有多少個batch
num_batches_per_epoch = int(num_examples/batch_size)
def sparse_tuple_from(sequences, dtype=np.int32):
"""得到一個list的稀疏表示,為了直接將資料賦值給tensorflow的tf.sparse_placeholder稀疏矩陣
Args:
sequences: 序列的列表
Returns:
一個三元組,和tensorflow的tf.sparse_placeholder同結構
"""
indices = []
values = []
for n, seq in enumerate(sequences):
indices.extend(zip([n]*len(seq), range(len(seq))))
values.extend(seq)
indices = np.asarray(indices, dtype=np.int64)
values = np.asarray(values, dtype=dtype)
shape = np.asarray([len(sequences), np.asarray(indices).max(0)[1]+1], dtype=np.int64)
return indices, values, shape
def get_audio_feature():
'''
獲取wav檔案提取mfcc特徵之後的資料
'''
audio_filename = "audio.wav"
#讀取wav檔案內容,fs為取樣率, audio為資料
fs, audio = wav.read(audio_filename)
#提取mfcc特徵
inputs = mfcc(audio, samplerate=fs)
# 對特徵資料進行歸一化,減去均值除以方差
feature_inputs = np.asarray(inputs[np.newaxis, :])
feature_inputs = (feature_inputs - np.mean(feature_inputs))/np.std(feature_inputs)
#特徵資料的序列長度
feature_seq_len = [feature_inputs.shape[1]]
return feature_inputs, feature_seq_len
def get_audio_label():
'''
將label文字轉換成整數序列,然後再換成稀疏三元組
'''
target_filename = 'label.txt'
with open(target_filename, 'r') as f:
#原始文字為“she had your dark suit in greasy wash water all year”
line = f.readlines()[0].strip()
targets = line.replace(' ', ' ')
# 放入list中,空格用''代替
#['she', '', 'had', '', 'your', '', 'dark', '', 'suit', '', 'in', '', 'greasy', '', 'wash', '', 'water', '', 'all', '', 'year']
targets = targets.split(' ')
# 每個字母作為一個label,轉換成如下:
#['s' 'h' 'e' '<space>' 'h' 'a' 'd' '<space>' 'y' 'o' 'u' 'r' '<space>' 'd'
# 'a' 'r' 'k' '<space>' 's' 'u' 'i' 't' '<space>' 'i' 'n' '<space>' 'g' 'r'
# 'e' 'a' 's' 'y' '<space>' 'w' 'a' 's' 'h' '<space>' 'w' 'a' 't' 'e' 'r'
#'<space>' 'a' 'l' 'l' '<space>' 'y' 'e' 'a' 'r']
targets = np.hstack([SPACE_TOKEN if x == '' else list(x) for x in targets])
# 將label轉換成整數序列表示:
# [19 8 5 0 8 1 4 0 25 15 21 18 0 4 1 18 11 0 19 21 9 20 0 9 14
# 0 7 18 5 1 19 25 0 23 1 19 8 0 23 1 20 5 18 0 1 12 12 0 25 5
# 1 18]
targets = np.asarray([SPACE_INDEX if x == SPACE_TOKEN else ord(x) - FIRST_INDEX
for x in targets])
# 將列表轉換成稀疏三元組
train_targets = sparse_tuple_from([targets])
return train_targets
def inference(inputs, seq_len):
'''
2層雙向LSTM的網路結構定義
Args:
inputs: 輸入資料,形狀是[batch_size, 序列最大長度,一幀特徵的個數13]
序列最大長度是指,一個樣本在轉成特徵矩陣之後儲存在一個矩陣中,
在n個樣本組成的batch中,因為不同的樣本的序列長度不一樣,在組成的3維資料中,
第2維的長度要足夠容納下所有的樣本的特徵序列長度。
seq_len: batch裡每個樣本的有效的序列長度
'''
#定義一個向前計算的LSTM單元,40個隱藏單元
cell_fw = tf.contrib.rnn.LSTMCell(num_hidden,
initializer=tf.random_normal_initializer(
mean=0.0, stddev=0.1),
state_is_tuple=True)
# 組成一個有2個cell的list
cells_fw = [cell_fw] * num_layers
# 定義一個向後計算的LSTM單元,40個隱藏單元
cell_bw = tf.contrib.rnn.LSTMCell(num_hidden,
initializer=tf.random_normal_initializer(
mean=0.0, stddev=0.1),
state_is_tuple=True)
# 組成一個有2個cell的list
cells_bw = [cell_bw] * num_layers
# 將前面定義向前計算和向後計算的2個cell的list組成雙向lstm網路
# sequence_length為實際有效的長度,大小為batch_size,
# 相當於表示batch中每個樣本的實際有用的序列長度有多長。
# 輸出的outputs寬度是隱藏單元的個數,即num_hidden的大小
outputs, _, _ = tf.contrib.rnn.stack_bidirectional_dynamic_rnn(cells_fw,
cells_bw,
inputs,
dtype=tf.float32,
sequence_length=seq_len)
#獲得輸入資料的形狀
shape = tf.shape(inputs)
batch_s, max_timesteps = shape[0], shape[1]
# 將2層LSTM的輸出轉換成寬度為40的矩陣
# 後面進行全連線計算
outputs = tf.reshape(outputs, [-1, num_hidden])
W = tf.Variable(tf.truncated_normal([num_hidden,
num_classes],
stddev=0.1))
b = tf.Variable(tf.constant(0., shape=[num_classes]))
# 進行全連線線性計算
logits = tf.matmul(outputs, W) + b
# 將全連線計算的結果,由寬度40變成寬度80,
# 即最後的輸入給CTC的資料寬度必須是26+2的寬度
logits = tf.reshape(logits, [batch_s, -1, num_classes])
# 轉置,將第一維和第二維交換。
# 變成序列的長度放第一維,batch_size放第二維。
# 也是為了適應Tensorflow的CTC的輸入格式
logits = tf.transpose(logits, (1, 0, 2))
return logits
def main():
# 輸入特徵資料,形狀為:[batch_size, 序列長度,一幀特徵數]
inputs = tf.placeholder(tf.float32, [None, None, num_features])
# 輸入資料的label,定義成稀疏sparse_placeholder會生成稀疏的tensor:SparseTensor
# 這個結構可以直接輸入給ctc求loss
targets = tf.sparse_placeholder(tf.int32)
# 序列的長度,大小是[batch_size]大小
# 表示的是batch中每個樣本的有效序列長度是多少
seq_len = tf.placeholder(tf.int32, [None])
# 向前計算網路,定義網路結構,輸入是特徵資料,輸出提供給ctc計算損失值。
logits = inference(inputs, seq_len)
# ctc計算損失
# 引數targets必須是一個值為int32的稀疏tensor的結構:tf.SparseTensor
# 引數logits是前面lstm網路的輸出
# 引數seq_len是這個batch的樣本中,每個樣本的序列長度。
loss = tf.nn.ctc_loss(targets, logits, seq_len)
# 計算損失的平均值
cost = tf.reduce_mean(loss)
# 採用衝量優化方法
optimizer = tf.train.MomentumOptimizer(initial_learning_rate, 0.9).minimize(cost)
# 還有另外一個ctc的函式:tf.contrib.ctc.ctc_beam_search_decoder
# 本函式會得到更好的結果,但是效果比ctc_beam_search_decoder低
# 返回的結果中,decode是ctc解碼的結果,即輸入的資料解碼出結果序列是什麼
decoded, _ = tf.nn.ctc_greedy_decoder(logits, seq_len)
# 採用計算編輯距離的方式計算,計算decode後結果的錯誤率。
ler = tf.reduce_mean(tf.edit_distance(tf.cast(decoded[0], tf.int32),
targets))
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
with tf.Session(config=config) as session:
# 初始化變數
tf.global_variables_initializer().run()
for curr_epoch in range(num_epochs):
train_cost = train_ler = 0
start = time.time()
for batch in range(num_batches_per_epoch):
#獲取訓練資料,本例中只去一個樣本的訓練資料
train_inputs, train_seq_len = get_audio_feature()
# 獲取這個樣本的label
train_targets = get_audio_label()
feed = {inputs: train_inputs,
targets: train_targets,
seq_len: train_seq_len}
# 一次訓練,更新引數
batch_cost, _ = session.run([cost, optimizer], feed)
# 計算累加的訓練的損失值
train_cost += batch_cost * batch_size
# 計算訓練集的錯誤率
train_ler += session.run(ler, feed_dict=feed)*batch_size
train_cost /= num_examples
train_ler /= num_examples
# 列印每一輪迭代的損失值,錯誤率
log = "Epoch {}/{}, train_cost = {:.3f}, train_ler = {:.3f}, time = {:.3f}"
print(log.format(curr_epoch+1, num_epochs, train_cost, train_ler,
time.time() - start))
# 在進行了1200次訓練之後,計算一次實際的測試,並且輸出
# 讀取測試資料,這裡讀取的和訓練資料的同一個樣本
test_inputs, test_seq_len = get_audio_feature()
test_targets = get_audio_label()
test_feed = {inputs: test_inputs,
targets: test_targets,
seq_len: test_seq_len}
d = session.run(decoded[0], feed_dict=test_feed)
# 將得到的測試語音經過ctc解碼後的整數序列轉換成字母
str_decoded = ''.join([chr(x) for x in np.asarray(d[1]) + FIRST_INDEX])
# 將no label轉換成空
str_decoded = str_decoded.replace(chr(ord('z') + 1), '')
# 將空白轉換成空格
str_decoded = str_decoded.replace(chr(ord('a') - 1), ' ')
# 列印最後的結果
print('Decoded:\n%s' % str_decoded)
if __name__ == "__main__":
main()
相關推薦
CTC loss 理解
前言:理解了很久的CTC,每次都是點到即止,所以一直沒有很明確,現在重新整理。 定義 CTC (Connectionist Temporal Classification)是一種loss function 對比 傳統方法 在傳統的
語音識別:深入理解CTC Loss原理
最近看了百度的Deep Speech,看到語音識別使用的損失函式是CTC loss。便整理了一下有關於CTC loss的一些定義和推導。由於個人水平有限,如果文章有錯誤,還懇請各位指出,萬分感謝~ 附上我的github主頁,歡迎各位的follow~~~
facenet:triplet-loss理解與train_tripletloss.py程式碼理解
對於Facenet進行人臉特徵提取,演算法內容較為核心和比較難以理解的地方在於三元損失函式Triplet-loss。 神經網路所要學習的目標是:使得Anchor到Positive的距離要比Anchor到Negative的距離要短(Anchor為一個樣本,Positive為與Anchor同類的
用於CTC loss的幾種解碼方法:貪心搜尋 (greedy search)、束搜尋(Beam Search)、字首束搜尋(Prefix Beam Search)
在CTC網路中我們可以訓練出一個對映: 假如序列目標為字串(詞表大小為 n),則Nw輸出為n維多項概率分佈。 網路輸出為:y=Nw,其中,表示t時刻輸出是第k項的概率。 但是這個輸出只是一組組概率,我們要由這個Nw得到我們預測的標籤,這就涉及到一個解碼的問題。 &nbs
解讀CTC LOSS原理
為什麼要使用CTC(Connectionist temporal classification): 在傳統的語音識別的聲學模型訓練中,對於每一幀的資料,我們需要知道對應的label才能進行有效的訓練,在訓練資料之前需要做語音對齊的預處理。對齊的預處理要花費大量的人力和時間,而且對齊之後,模型
YOLO loss理解
自己理解的YOLO loss 是 對於label有物體的框,不管預測有沒有,都需要計算位置(座標)損失,權重大一點。所有框都計算判別概率損失,無物體的框 權重小一點,對於label有物體的框,計算預測損失。
關於對比損失(contrasive loss)的理解(相似度越大越相似的情況):
def contro_loss(self): ''' 總結下來對比損失的特點:首先看標籤,然後標籤為1是正對,負對部分損失為0,最小化總損失就是最小化類內損失(within_loss)部分, 讓s逼近margin的過程,是個增大的過程;標籤為0
理解contrastive loss
因為最近看normL2face 看到中途發現作者其中有個創新點是對contrastive loss 和triple loss 進行了改動,由於之前只是草草的瞭解了contrastive loss ,為了更好地探究作者的創新出發點 ,看了contrastive loss 的論文 Dimensi
何愷明大神的「Focal Loss」,如何更好地理解?
轉自:http://blog.csdn.net/c9Yv2cf9I06K2A9E/article/details/78920998 作者丨蘇劍林 單位丨廣州火焰資訊科技有限公司 研究方向丨NLP,神經網路 個人主頁丨kexue.fm 前言
focal loss 兩點理解
png 感覺 技術 src 類別 com 大量 。。 ima 博客給出了三個算例。 可以看出,focal loss 對可很好分類的樣本賦予了較小的權重,但是對分錯和不易分的樣本添加了較大的權重。 對於類別不平衡,使用了$\alpha_t$進行加權,文章中提到較好的值是0
深度學習基礎--loss與啟用函式--CTC(Connectionist temporal classification)的loss
CTC(Connectionist temporal classification)的loss 用在online sequence。由於需要在分類結果中新增一個{no gesture}的類別,如果用在segmented video的分類時,需要去掉這類(因為視訊總屬於某個類)。
交叉熵在loss函式中使用的理解
交叉熵(cross entropy)是深度學習中常用的一個概念,一般用來求目標與預測值之間的差距。以前做一些分類問題的時候,沒有過多的注意,直接呼叫現成的庫,用起來也比較方便。最近開始研究起對抗生成網路(GANs),用到了交叉熵,發現自己對交叉熵的理解有些模糊,不夠深入。遂花了幾天的時間從頭梳理了一下相關
hinge loss/支援向量損失的理解
線性分類器損失函式與最優化 假設有3類 cat car frog 第一列第二行的5.1表示真實類別為cat,然後分類器判斷為car的的分數為5.1。 那這裡的這個loss怎麼去計算呢? 這裡就要介紹下SVM的損失函式,叫hinge loss。 如上圖所示,我
Focal Loss 的理解
論文:《Focal Loss for Dense Object Detection》 Focal Loss 是何愷明設計的為了解決one-stage目標檢測在訓練階段前景類和背景類極度不均衡(如1:1000)的場景的損失函式。它是由二分類交叉熵改造而來的。 標準交叉熵 其中,p是模型預測屬於類別y=
【論文理解】ArcFace: Additive Angular Margin Loss for Deep Face Recognition(InsightFace)
這篇論文基本介紹了近期較為流行的人臉識別模型,loss變化從softmax一路捋到CosFace,然後提出ArcFace,可以說起到很好的綜述作用。論文評價對比方面也做了非常詳細的對比策略方案分析。資料清洗工作也對後續研究應用有較大意義。資料和程式碼都開源,相當良心。本文主要
pytorch中網路loss傳播和引數更新理解
相比於2018年,在ICLR2019提交論文中,提及不同框架的論文數量發生了極大變化,網友發現,提及tensorflow的論文數量從2018年的228篇略微提升到了266篇,keras從42提升到56,但是pytorch的數量從87篇提升到了252篇。 TensorFlow: 228--->
Focal Loss 論文理解及公式推導
作者: Tsung-Yi, Lin, Priya Goyal, Ross Girshick, Kaiming He, Piotr Dollar 團隊: FAIR 精度最高的目標檢測器往往基於 RCNN 的 two-stage 方法,對候選目標位置再採用
GAN的Loss的比較研究(1)——傳統GAN的Loss的理解1
GAN(Generative Adversarial Network)由兩個網路組成:Generator網路(生成網路,簡稱G)、Discriminator網路(判別網路,簡稱D),如圖: 圖1 GAN概念圖 因而有兩個Loss:Loss_D(判別網路損失函式
【論文筆記4】深入理解行人重識別網路的Loss
打完天池比賽後,可能由於長時間的持續輸出,精神上有些疲憊感,於是選擇去幹一些不是很費腦力的活兒,比如繼續充充電,看些論文補充一些理論知識。這兩天看了幾篇羅老師部落格裡總結的Person Re-Identification這塊的論文,包括羅老師自己發的兩篇論文。幾篇論文中都用到
從極大似然估計的角度理解深度學習中loss函式
從極大似然估計的角度理解深度學習中loss函式 為了理解這一概念,首先回顧下最大似然估計的概念: 最大似然估計常用於利用已知的樣本結果,反推最有可能導致這一結果產生的引數值,往往模型結果已經確定,用於反推模型中的引數.即在引數空間中選擇最有可能導致樣本結果發生的引數.因為結果已知,則某一引數使得結果產生的概率