<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # 如何用Keras開發用于Python序列分類的雙向LSTM > 原文: [https://machinelearningmastery.com/develop-bidirectional-lstm-sequence-classification-python-keras/](https://machinelearningmastery.com/develop-bidirectional-lstm-sequence-classification-python-keras/) 雙向LSTM是傳統LSTM的擴展,可以提高序列分類問題的模型表現。 在輸入序列的所有時間步長都可用的問題中,雙向LSTM在輸入序列上訓練兩個而不是一個LSTM。輸入序列中的第一個是原樣,第二個是輸入序列的反向副本。這可以為網絡提供額外的上下文,從而更快,更全面地學習問題。 在本教程中,您將了解如何使用Keras深度學習庫在Python中開發用于序列分類的雙向LSTM。 完成本教程后,您將了解: * 如何開發一個小的人為和可配置的序列分類問題。 * 如何開發LSTM和雙向LSTM用于序列分類。 * 如何比較雙向LSTM中使用的合并模式的表現。 讓我們開始吧。 ![How to Develop a Bidirectional LSTM For Sequence Classification in Python with Keras](img/631a4b73518c1108a1916e6a03b5e398.jpg) 如何使用Keras開發用于Python序列分類的雙向LSTM 照片由 [Cristiano Medeiros Dalbem](https://www.flickr.com/photos/helloninja/15333087540/) ,保留一些權利。 ## 概觀 本教程分為6個部分;他們是: 1. 雙向LSTM 2. 序列分類問題 3. LSTM用于序列分類 4. 用于序列分類的雙向LSTM 5. 將LSTM與雙向LSTM進行比較 6. 比較雙向LSTM合并模式 ### 環境 本教程假定您已安裝Python SciPy環境。您可以在此示例中使用Python 2或3。 本教程假設您使用TensorFlow(v1.1.0 +)或Theano(v0.9 +)后端安裝了Keras(v2.0.4 +)。 本教程還假設您安裝了scikit-learn,Pandas,NumPy和Matplotlib。 如果您在設置Python環境時需要幫助,請參閱以下帖子: * [如何使用Anaconda設置用于機器學習和深度學習的Python環境](http://machinelearningmastery.com/setup-python-environment-machine-learning-deep-learning-anaconda/) ## 雙向LSTM 雙向循環神經網絡(RNN)的想法很簡單。 它涉及復制網絡中的第一個復現層,以便現在有兩個并排的層,然后按原樣提供輸入序列作為第一層的輸入,并將輸入序列的反向副本提供給第二層。 > 為了克服常規RNN的局限性,我們提出了一種雙向循環神經網絡(BRNN),可以在特定時間范圍的過去和未來使用所有可用的輸入信息進行訓練。 > > ... > > 這個想法是將常規RNN的狀態神經元分成負責正時間方向的部分(前向狀態)和負時間方向的部分(后向狀態)。 - Mike Schuster和Kuldip K. Paliwal,[雙向循環神經網絡](https://maxwell.ict.griffith.edu.au/spl/publications/papers/ieeesp97_schuster.pdf),1997 這種方法已被用于長期短期記憶(LSTM)循環神經網絡的巨大效果。 最初在語音識別領域中使用雙向提供序列是合理的,因為有證據表明整個話語的語境用于解釋所說的內容而不是線性解釋。 > ...依賴于對未來的了解似乎乍一看違反了因果關系。我們怎樣才能將我們所聽到的東西的理解基于尚未說過的東西?然而,人類聽眾正是這樣做的。根據未來的背景,聽起來,單詞甚至整個句子最初都意味著沒有任何意義。我們必須記住的是真正在線的任務之間的區別 - 在每次輸入后需要輸出 - 以及僅在某些輸入段結束時需要輸出的任務。 - Alex Graves和Jurgen Schmidhuber,[具有雙向LSTM和其他神經網絡架構的Framewise音素分類](ftp://ftp.idsia.ch/pub/juergen/nn_2005.pdf),2005 雙向LSTM的使用對于所有序列預測問題可能沒有意義,但是對于那些適當的域,可以提供更好的結果。 > 我們發現雙向網絡比單向網絡明顯更有效...... — Alex Graves and Jurgen Schmidhuber, [Framewise Phoneme Classification with Bidirectional LSTM and Other Neural Network Architectures](ftp://ftp.idsia.ch/pub/juergen/nn_2005.pdf), 2005 需要說明的是,輸入序列中的時間步長仍然是一次處理一次,只是網絡同時在兩個方向上逐步通過輸入序列。 ### Keras中的雙向LSTM Keras通過[雙向](https://keras.io/layers/wrappers/#bidirectional)層包裝器支持雙向LSTM。 該包裝器將循環層(例如第一個LSTM層)作為參數。 它還允許您指定合并模式,即在傳遞到下一層之前應如何組合前向和后向輸出。選項是: * ' _sum_ ':輸出加在一起。 * ' _mul_ ':輸出相乘。 * ' _concat_ ':輸出連接在一起(默認值),為下一層提供兩倍的輸出。 * ' _ave_ ':輸出的平均值。 默認模式是連接,這是雙向LSTM研究中經常使用的方法。 ## 序列分類問題 我們將定義一個簡單的序列分類問題來探索雙向LSTM。 該問題被定義為0和1之間的隨機值序列。該序列被作為問題的輸入,每個時間步提供一個數字。 二進制標簽(0或1)與每個輸入相關聯。輸出值均為0.一旦序列中輸入值的累積和超過閾值,則輸出值從0翻轉為1。 使用序列長度的1/4的閾值。 例如,下面是10個輸入時間步長(X)的序列: ```py 0.63144003 0.29414551 0.91587952 0.95189228 0.32195638 0.60742236 0.83895793 0.18023048 0.84762691 0.29165514 ``` 相應的分類輸出(y)將是: ```py 0 0 0 1 1 1 1 1 1 1 ``` 我們可以用Python實現它。 第一步是生成一系列隨機值。我們可以使用隨機模塊中的 [random()函數](https://docs.python.org/3/library/random.html)。 ```py # create a sequence of random numbers in [0,1] X = array([random() for _ in range(10)]) ``` 我們可以將閾值定義為輸入序列長度的四分之一。 ```py # calculate cut-off value to change class values limit = 10/4.0 ``` 可以使用 [cumsum()NumPy函數](https://docs.scipy.org/doc/numpy/reference/generated/numpy.cumsum.html)計算輸入序列的累積和。此函數返回一系列累積和值,例如: ```py pos1, pos1+pos2, pos1+pos2+pos3, ... ``` 然后我們可以計算輸出序列,確定每個累積和值是否超過閾值。 ```py # determine the class outcome for each item in cumulative sequence y = array([0 if x < limit else 1 for x in cumsum(X)]) ``` 下面的函數名為get_sequence(),將所有這些一起繪制,將序列的長度作為輸入,并返回新問題案例的X和y分量。 ```py from random import random from numpy import array from numpy import cumsum # create a sequence classification instance def get_sequence(n_timesteps): # create a sequence of random numbers in [0,1] X = array([random() for _ in range(n_timesteps)]) # calculate cut-off value to change class values limit = n_timesteps/4.0 # determine the class outcome for each item in cumulative sequence y = array([0 if x < limit else 1 for x in cumsum(X)]) return X, y ``` 我們可以使用新的10個步驟序列測試此函數,如下所示: ```py X, y = get_sequence(10) print(X) print(y) ``` 首先運行該示例打印生成的輸入序列,然后輸出匹配的輸出序列。 ```py [ 0.22228819 0.26882207 0.069623 0.91477783 0.02095862 0.71322527 0.90159654 0.65000306 0.88845226 0.4037031 ] [0 0 0 0 0 0 1 1 1 1] ``` ## LSTM用于序列分類 我們可以從為序列分類問題開發傳統的LSTM開始。 首先,我們必須更新get_sequence()函數以將輸入和輸出序列重新整形為3維以滿足LSTM的期望。預期結構具有尺寸[樣本,時間步長,特征]。分類問題具有1個樣本(例如,一個序列),可配置的時間步長,以及每個時間步長一個特征。 分類問題具有1個樣本(例如,一個序列),可配置的時間步長,以及每個時間步長一個特征。 因此,我們可以如下重塑序列。 ```py # reshape input and output data to be suitable for LSTMs X = X.reshape(1, n_timesteps, 1) y = y.reshape(1, n_timesteps, 1) ``` 更新后的get_sequence()函數如下所示。 ```py # create a sequence classification instance def get_sequence(n_timesteps): # create a sequence of random numbers in [0,1] X = array([random() for _ in range(n_timesteps)]) # calculate cut-off value to change class values limit = n_timesteps/4.0 # determine the class outcome for each item in cumulative sequence y = array([0 if x < limit else 1 for x in cumsum(X)]) # reshape input and output data to be suitable for LSTMs X = X.reshape(1, n_timesteps, 1) y = y.reshape(1, n_timesteps, 1) return X, y ``` 我們將序列定義為具有10個時間步長。 接下來,我們可以為問題定義LSTM。輸入層將有10個時間步長,1個特征是一個片段,input_shape =(10,1)。 第一個隱藏層將具有20個存儲器單元,輸出層將是完全連接的層,每個時間步輸出一個值。在輸出上使用sigmoid激活函數來預測二進制值。 在輸出層周圍使用TimeDistributed包裝層,以便在給定作為輸入提供的完整序列的情況下,可以預測每個時間步長一個值。這要求LSTM隱藏層返回一系列值(每個時間步長一個)而不是整個輸入序列的單個值。 最后,因為這是二元分類問題,所以使用二進制日志丟失(Keras中的binary_crossentropy)。使用有效的ADAM優化算法來找到權重,并且計算每個時期的精度度量并報告。 ```py # define LSTM model = Sequential() model.add(LSTM(20, input_shape=(10, 1), return_sequences=True)) model.add(TimeDistributed(Dense(1, activation='sigmoid'))) model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['acc']) ``` LSTM將接受1000個時期的訓練。將在每個時期生成新的隨機輸入序列以使網絡適合。這可以確保模型不記憶單個序列,而是可以推廣解決方案以解決此問題的所有可能的隨機輸入序列。 ```py # train LSTM for epoch in range(1000): # generate new random sequence X,y = get_sequence(n_timesteps) # fit model for one epoch on this sequence model.fit(X, y, epochs=1, batch_size=1, verbose=2) ``` 一旦經過訓練,網絡將在另一個隨機序列上進行評估。然后將預測與預期輸出序列進行比較,以提供系統技能的具體示例。 ```py # evaluate LSTM X,y = get_sequence(n_timesteps) yhat = model.predict_classes(X, verbose=0) for i in range(n_timesteps): print('Expected:', y[0, i], 'Predicted', yhat[0, i]) ``` 下面列出了完整的示例。 ```py from random import random from numpy import array from numpy import cumsum from keras.models import Sequential from keras.layers import LSTM from keras.layers import Dense from keras.layers import TimeDistributed # create a sequence classification instance def get_sequence(n_timesteps): # create a sequence of random numbers in [0,1] X = array([random() for _ in range(n_timesteps)]) # calculate cut-off value to change class values limit = n_timesteps/4.0 # determine the class outcome for each item in cumulative sequence y = array([0 if x < limit else 1 for x in cumsum(X)]) # reshape input and output data to be suitable for LSTMs X = X.reshape(1, n_timesteps, 1) y = y.reshape(1, n_timesteps, 1) return X, y # define problem properties n_timesteps = 10 # define LSTM model = Sequential() model.add(LSTM(20, input_shape=(n_timesteps, 1), return_sequences=True)) model.add(TimeDistributed(Dense(1, activation='sigmoid'))) model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['acc']) # train LSTM for epoch in range(1000): # generate new random sequence X,y = get_sequence(n_timesteps) # fit model for one epoch on this sequence model.fit(X, y, epochs=1, batch_size=1, verbose=2) # evaluate LSTM X,y = get_sequence(n_timesteps) yhat = model.predict_classes(X, verbose=0) for i in range(n_timesteps): print('Expected:', y[0, i], 'Predicted', yhat[0, i]) ``` 運行該示例在每個時期的隨機序列上打印日志丟失和分類準確性。 這清楚地表明了模型對序列分類問題的解決方案的概括性。 我們可以看到該模型表現良好,達到最終準確度,徘徊在90%左右,準確率達到100%。不完美,但對我們的目的有好處。 將新隨機序列的預測與預期值進行比較,顯示出具有單個錯誤的大多數正確結果。 ```py ... Epoch 1/1 0s - loss: 0.2039 - acc: 0.9000 Epoch 1/1 0s - loss: 0.2985 - acc: 0.9000 Epoch 1/1 0s - loss: 0.1219 - acc: 1.0000 Epoch 1/1 0s - loss: 0.2031 - acc: 0.9000 Epoch 1/1 0s - loss: 0.1698 - acc: 0.9000 Expected: [0] Predicted [0] Expected: [0] Predicted [0] Expected: [0] Predicted [0] Expected: [0] Predicted [0] Expected: [0] Predicted [0] Expected: [0] Predicted [1] Expected: [1] Predicted [1] Expected: [1] Predicted [1] Expected: [1] Predicted [1] Expected: [1] Predicted [1] ``` ## 用于序列分類的雙向LSTM 現在我們知道如何為序列分類問題開發LSTM,我們可以擴展該示例來演示雙向LSTM。 我們可以通過使用雙向層包裝LSTM隱藏層來完成此操作,如下所示: ```py model.add(Bidirectional(LSTM(20, return_sequences=True), input_shape=(n_timesteps, 1))) ``` 這將創建隱藏層的兩個副本,一個適合輸入序列,一個適合輸入序列的反向副本。默認情況下,將連接這些LSTM的輸出值。 這意味著,而不是TimeDistributed層接收10個時間段的20個輸出,它現在將接收10個時間段的40(20個單位+ 20個單位)輸出。 The complete example is listed below. ```py from random import random from numpy import array from numpy import cumsum from keras.models import Sequential from keras.layers import LSTM from keras.layers import Dense from keras.layers import TimeDistributed from keras.layers import Bidirectional # create a sequence classification instance def get_sequence(n_timesteps): # create a sequence of random numbers in [0,1] X = array([random() for _ in range(n_timesteps)]) # calculate cut-off value to change class values limit = n_timesteps/4.0 # determine the class outcome for each item in cumulative sequence y = array([0 if x < limit else 1 for x in cumsum(X)]) # reshape input and output data to be suitable for LSTMs X = X.reshape(1, n_timesteps, 1) y = y.reshape(1, n_timesteps, 1) return X, y # define problem properties n_timesteps = 10 # define LSTM model = Sequential() model.add(Bidirectional(LSTM(20, return_sequences=True), input_shape=(n_timesteps, 1))) model.add(TimeDistributed(Dense(1, activation='sigmoid'))) model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['acc']) # train LSTM for epoch in range(1000): # generate new random sequence X,y = get_sequence(n_timesteps) # fit model for one epoch on this sequence model.fit(X, y, epochs=1, batch_size=1, verbose=2) # evaluate LSTM X,y = get_sequence(n_timesteps) yhat = model.predict_classes(X, verbose=0) for i in range(n_timesteps): print('Expected:', y[0, i], 'Predicted', yhat[0, i]) ``` 運行該示例,我們看到與前一個示例中類似的輸出。 雙向LSTM的使用具有允許LSTM更快地學習問題的效果。 通過在運行結束時查看模型的技能,而不是模型的技能,這一點并不明顯。 ```py ... Epoch 1/1 0s - loss: 0.0967 - acc: 0.9000 Epoch 1/1 0s - loss: 0.0865 - acc: 1.0000 Epoch 1/1 0s - loss: 0.0905 - acc: 0.9000 Epoch 1/1 0s - loss: 0.2460 - acc: 0.9000 Epoch 1/1 0s - loss: 0.1458 - acc: 0.9000 Expected: [0] Predicted [0] Expected: [0] Predicted [0] Expected: [0] Predicted [0] Expected: [0] Predicted [0] Expected: [0] Predicted [0] Expected: [1] Predicted [1] Expected: [1] Predicted [1] Expected: [1] Predicted [1] Expected: [1] Predicted [1] Expected: [1] Predicted [1] ``` ## 將LSTM與雙向LSTM進行比較 在此示例中,我們將在模型正在訓練期間比較傳統LSTM與雙向LSTM的表現。 我們將調整實驗,以便模型僅訓練250個時期。這樣我們就可以清楚地了解每個模型的學習方式以及學習行為與雙向LSTM的不同之處。 我們將比較三種不同的模型;特別: 1. LSTM(原樣) 2. 具有反向輸入序列的LSTM(例如,您可以通過將LSTM層的“go_backwards”參數設置為“True”來執行此操作) 3. 雙向LSTM 這種比較將有助于表明雙向LSTM實際上可以添加的東西不僅僅是簡單地反轉輸入序列。 我們將定義一個函數來創建和返回帶有前向或后向輸入序列的LSTM,如下所示: ```py def get_lstm_model(n_timesteps, backwards): model = Sequential() model.add(LSTM(20, input_shape=(n_timesteps, 1), return_sequences=True, go_backwards=backwards)) model.add(TimeDistributed(Dense(1, activation='sigmoid'))) model.compile(loss='binary_crossentropy', optimizer='adam') return model ``` 我們可以為雙向LSTM開發類似的函數,其中可以將合并模式指定為參數。可以通過將合并模式設置為值'concat'來指定串聯的默認值。 ```py def get_bi_lstm_model(n_timesteps, mode): model = Sequential() model.add(Bidirectional(LSTM(20, return_sequences=True), input_shape=(n_timesteps, 1), merge_mode=mode)) model.add(TimeDistributed(Dense(1, activation='sigmoid'))) model.compile(loss='binary_crossentropy', optimizer='adam') return model ``` 最后,我們定義一個函數來擬合模型并檢索和存儲每個訓練時期的損失,然后在模型擬合后返回收集的損失值的列表。這樣我們就可以繪制每個模型配置的日志丟失圖并進行比較。 ```py def train_model(model, n_timesteps): loss = list() for _ in range(250): # generate new random sequence X,y = get_sequence(n_timesteps) # fit model for one epoch on this sequence hist = model.fit(X, y, epochs=1, batch_size=1, verbose=0) loss.append(hist.history['loss'][0]) return loss ``` 綜合這些,下面列出了完整的例子。 首先,創建并擬合傳統的LSTM并繪制對數損失值。使用具有反向輸入序列的LSTM重復此操作,最后使用具有級聯合并的LSTM重復此操作。 ```py from random import random from numpy import array from numpy import cumsum from matplotlib import pyplot from pandas import DataFrame from keras.models import Sequential from keras.layers import LSTM from keras.layers import Dense from keras.layers import TimeDistributed from keras.layers import Bidirectional # create a sequence classification instance def get_sequence(n_timesteps): # create a sequence of random numbers in [0,1] X = array([random() for _ in range(n_timesteps)]) # calculate cut-off value to change class values limit = n_timesteps/4.0 # determine the class outcome for each item in cumulative sequence y = array([0 if x < limit else 1 for x in cumsum(X)]) # reshape input and output data to be suitable for LSTMs X = X.reshape(1, n_timesteps, 1) y = y.reshape(1, n_timesteps, 1) return X, y def get_lstm_model(n_timesteps, backwards): model = Sequential() model.add(LSTM(20, input_shape=(n_timesteps, 1), return_sequences=True, go_backwards=backwards)) model.add(TimeDistributed(Dense(1, activation='sigmoid'))) model.compile(loss='binary_crossentropy', optimizer='adam') return model def get_bi_lstm_model(n_timesteps, mode): model = Sequential() model.add(Bidirectional(LSTM(20, return_sequences=True), input_shape=(n_timesteps, 1), merge_mode=mode)) model.add(TimeDistributed(Dense(1, activation='sigmoid'))) model.compile(loss='binary_crossentropy', optimizer='adam') return model def train_model(model, n_timesteps): loss = list() for _ in range(250): # generate new random sequence X,y = get_sequence(n_timesteps) # fit model for one epoch on this sequence hist = model.fit(X, y, epochs=1, batch_size=1, verbose=0) loss.append(hist.history['loss'][0]) return loss n_timesteps = 10 results = DataFrame() # lstm forwards model = get_lstm_model(n_timesteps, False) results['lstm_forw'] = train_model(model, n_timesteps) # lstm backwards model = get_lstm_model(n_timesteps, True) results['lstm_back'] = train_model(model, n_timesteps) # bidirectional concat model = get_bi_lstm_model(n_timesteps, 'concat') results['bilstm_con'] = train_model(model, n_timesteps) # line plot of results results.plot() pyplot.show() ``` 運行該示例會創建一個線圖。 您的具體情節可能會有所不同,但會顯示相同的趨勢。 我們可以看到LSTM前向(藍色)和LSTM后向(橙色)在250個訓練時期內顯示出類似的對數丟失。 我們可以看到雙向LSTM日志丟失是不同的(綠色),更快地下降到更低的值并且通常保持低于其他兩個配置。 ![Line Plot of Log Loss for an LSTM, Reversed LSTM and a Bidirectional LSTM](img/4cd1590873b3cae68ce059142bdc8116.jpg) LSTM,反向LSTM和雙向LSTM的對數損失線圖 ## 比較雙向LSTM合并模式 有4種不同的合并模式可用于組合雙向LSTM層的結果。 它們是串聯(默認),乘法,平均和總和。 我們可以通過更新上一節中的示例來比較不同合并模式的行為,如下所示: ```py n_timesteps = 10 results = DataFrame() # sum merge model = get_bi_lstm_model(n_timesteps, 'sum') results['bilstm_sum'] = train_model(model, n_timesteps) # mul merge model = get_bi_lstm_model(n_timesteps, 'mul') results['bilstm_mul'] = train_model(model, n_timesteps) # avg merge model = get_bi_lstm_model(n_timesteps, 'ave') results['bilstm_ave'] = train_model(model, n_timesteps) # concat merge model = get_bi_lstm_model(n_timesteps, 'concat') results['bilstm_con'] = train_model(model, n_timesteps) # line plot of results results.plot() pyplot.show() ``` 運行該示例將創建比較每個合并模式的日志丟失的線圖。 您的具體情節可能有所不同,但會顯示相同的行為趨勢。 不同的合并模式會導致不同的模型表現,這將根據您的特定序列預測問題而變化。 在這種情況下,我們可以看到,總和(藍色)和串聯(紅色)合并模式可能會帶來更好的表現,或至少更低的日志丟失。 ![Line Plot to Compare Merge Modes for Bidirectional LSTMs](img/9ae482cd06b7f3fb0a05538df68a21b8.jpg) 線圖用于比較雙向LSTM的合并模式 ## 摘要 在本教程中,您了解了如何使用Keras在Python中開發用于序列分類的雙向LSTM。 具體來說,你學到了: * 如何開發一個人為的序列分類問題。 * 如何開發LSTM和雙向LSTM用于序列分類。 * 如何比較雙向LSTM的合并模式以進行序列分類。 你有任何問題嗎? 在下面的評論中提出您的問題,我會盡力回答。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看