Python 3 & Keras 實(shí)現(xiàn)基于神經(jīng)網(wǎng)絡(luò)的交通流預(yù)測(cè)

交通流量預(yù)測(cè)在智能交通(ITS)系統(tǒng)中占有重要地位兵拢,是實(shí)現(xiàn)交通誘導(dǎo)的前提翻斟。準(zhǔn)確實(shí)時(shí)的短時(shí)交通流預(yù)測(cè)有助于更好的分析路網(wǎng)交通狀況,對(duì)路網(wǎng)交通規(guī)劃和交通優(yōu)化控制有非常重要的作用说铃。隨著交通數(shù)據(jù)采集技術(shù)的不斷發(fā)展访惜,及時(shí)獲取路網(wǎng)中實(shí)時(shí)的交通數(shù)據(jù)已成為可能嘹履,大量的交通信息為基于深度學(xué)習(xí)的預(yù)測(cè)模型提供了數(shù)據(jù)保障。
基于神經(jīng)網(wǎng)絡(luò)的交通流預(yù)測(cè)的相關(guān)研究如下列論文所示债热。由于與我的研究方向相關(guān)砾嫉,在本文中我實(shí)現(xiàn)了基于SAEs、RNN的交通流量預(yù)測(cè)模型窒篱。

Paper
Traffic Flow Prediction With Big Data: A Deep Learning Approach
Using LSTM and GRU neural network methods for traffic flow prediction

Githubhttps://github.com/xiaochus/TrafficFlowPrediction

環(huán)境

  • Python 3.5
  • Tensorflow-gpu 1.2.0
  • Keras 2.1.3
  • scikit-learn 0.18

數(shù)據(jù)處理

實(shí)驗(yàn)數(shù)據(jù)是從Caltrans Performance Measurement System (PeMS)獲取的焕刮。原始的流量數(shù)據(jù)是一個(gè)長(zhǎng)度為n的一維數(shù)據(jù)。我們首先使用訓(xùn)練集的數(shù)據(jù)實(shí)現(xiàn)一個(gè)標(biāo)準(zhǔn)化對(duì)象scaler墙杯,然后使用scaler分別對(duì)訓(xùn)練集與測(cè)試集進(jìn)行標(biāo)準(zhǔn)化配并。
由于時(shí)序預(yù)測(cè)任務(wù)需要使用歷史數(shù)據(jù)對(duì)未來(lái)數(shù)據(jù)進(jìn)行預(yù)測(cè),我們使用時(shí)滯變量lags對(duì)數(shù)據(jù)進(jìn)行劃分高镐,最后獲得大小為(samples, lags)的數(shù)據(jù)集溉旋。
劃分好的數(shù)據(jù)集在排列順序上依舊帶有時(shí)序特性,雖然keras在訓(xùn)練時(shí)可以選擇對(duì)數(shù)據(jù)進(jìn)行混洗嫉髓,但是其執(zhí)行順序是先對(duì)val數(shù)據(jù)進(jìn)行采樣再進(jìn)行混洗观腊,采樣過(guò)程依舊是按照順序來(lái)的。因此我們事先使用np.random.shuffle對(duì)數(shù)據(jù)進(jìn)行混洗岩喷,打亂數(shù)據(jù)的順序恕沫。

def process_data(train, test, lags):
    """Process data
    Reshape and split train\test data.

    # Arguments
        train: String, name of .csv train file.
        test: String, name of .csv test file.
        lags: integer, time lag.
    # Returns
        X_train: ndarray.
        y_train: ndarray.
        X_test: ndarray.
        y_test: ndarray.
        scaler: StandardScaler.
    """
    attr = 'Lane 1 Flow (Veh/5 Minutes)'
    df1 = pd.read_csv(train, encoding='utf-8').fillna(0)
    df2 = pd.read_csv(test, encoding='utf-8').fillna(0)

    # scaler = StandardScaler().fit(df1[attr].values)
    scaler = MinMaxScaler(feature_range=(0, 1)).fit(df1[attr].values)
    flow1 = scaler.transform(df1[attr].values)
    flow2 = scaler.transform(df2[attr].values)

    train, test = [], []
    for i in range(lags, len(flow1)):
        train.append(flow1[i - lags: i + 1])
    for i in range(lags, len(flow2)):
        test.append(flow2[i - lags: i + 1])

    train = np.array(train)
    test = np.array(test)
    np.random.shuffle(train)

    X_train = train[:, :-1]
    y_train = train[:, -1]
    X_test = test[:, :-1]
    y_test = test[:, -1]

    return X_train, y_train, X_test, y_test, scaler

模型

LSTM

2隱層LSTM網(wǎng)絡(luò)。

LSTM.png
def get_lstm(units):
    """LSTM(Long Short-Term Memory)
    Build LSTM Model.

    # Arguments
        units: List(int), number of input, output and hidden units.
    # Returns
        model: Model, nn model.
    """

    model = Sequential()
    model.add(LSTM(units[1], input_shape=(units[0], 1), return_sequences=True))
    model.add(LSTM(units[2]))
    model.add(Dropout(0.2))
    model.add(Dense(units[3], activation='linear'))

    return model

GRU

2隱層GRU網(wǎng)絡(luò)纱意。

GRU.png
def get_gru(units):
    """GRU(Gated Recurrent Unit)
    Build GRU Model.

    # Arguments
        units: List(int), number of input, output and hidden units.
    # Returns
        model: Model, nn model.
    """

    model = Sequential()
    model.add(GRU(units[1], input_shape=(units[0], 1), return_sequences=True))
    model.add(GRU(units[2]))
    model.add(Dropout(0.2))
    model.add(Dense(units[3], activation='linear'))

    return model

SAEs

SAEs.png

Auto-Encoders的原理是先通過(guò)一個(gè)encode層對(duì)輸入進(jìn)行編碼婶溯,這個(gè)編碼就是特征,然后利用encode乘第2層參數(shù)(也可以是encode層的參數(shù)的轉(zhuǎn)置乘特征并加偏執(zhí))偷霉,重構(gòu)(解碼)輸入迄委,然后用重構(gòu)的輸入和實(shí)際輸入的損失訓(xùn)練參數(shù)。
這里我們構(gòu)建了三個(gè)單獨(dú)的自動(dòng)編碼器类少,并按照相同的隱層結(jié)構(gòu)構(gòu)建了一個(gè)三層的SAEs叙身。

def _get_sae(inputs, hidden, output):
    """SAE(Auto-Encoders)
    Build SAE Model.

    # Arguments
        inputs: Integer, number of input units.
        hidden: Integer, number of hidden units.
        output: Integer, number of output units.
    # Returns
        model: Model, nn model.
    """

    model = Sequential()
    model.add(Dense(hidden, input_dim=inputs, name='hidden'))
    model.add(Activation('sigmoid'))
    model.add(Dropout(0.2))
    model.add(Dense(output))

    return model


def get_saes(layers):
    """SAEs(Stacked Auto-Encoders)
    Build SAEs Model.

    # Arguments
        layers: List(int), number of input, output and hidden units.
    # Returns
        models: List(Model), List of SAE and SAEs.
    """
    sae1 = _get_sae(layers[0], layers[1], layers[-1])
    sae2 = _get_sae(layers[1], layers[2], layers[-1])
    sae3 = _get_sae(layers[2], layers[3], layers[-1])

    saes = Sequential()
    saes.add(Dense(layers[1], input_dim=layers[0], name='hidden1'))
    saes.add(Activation('sigmoid'))
    saes.add(Dense(layers[2], name='hidden2'))
    saes.add(Activation('sigmoid'))
    saes.add(Dense(layers[3], name='hidden3'))
    saes.add(Activation('sigmoid'))
    saes.add(Dropout(0.2))
    saes.add(Dense(layers[4]))

    models = [sae1, sae2, sae3, saes]

    return models

訓(xùn)練

LSTM、GRU按照正常的RNN網(wǎng)絡(luò)進(jìn)行訓(xùn)練硫狞。使用train_model()函數(shù)訓(xùn)練信轿。
SAEs的訓(xùn)練過(guò)程:多個(gè)SAE分別訓(xùn)練,第一個(gè)SAE訓(xùn)練完之后残吩,其encode的輸出作為第二個(gè)SAE的輸入财忽,接著訓(xùn)練。最后訓(xùn)練完后泣侮,將所有SAE的中間隱層連接起來(lái)組成一個(gè)SAEs網(wǎng)絡(luò)即彪,使用之前的權(quán)值作為初始化權(quán)值,再對(duì)整個(gè)網(wǎng)絡(luò)進(jìn)行fine-tune活尊。使用train_seas()函數(shù)訓(xùn)練隶校。

使用RMSprop(lr=0.001, rho=0.9, epsilon=1e-06)作為優(yōu)化器漏益,batch_szie為256,lags為12(即時(shí)滯長(zhǎng)度為一個(gè)小時(shí))深胳。

def train_model(model, X_train, y_train, name, config):
    """train
    train a single model.

    # Arguments
        model: Model, NN model to train.
        X_train: ndarray(number, lags), Input data for train.
        y_train: ndarray(number, ), result data for train.
        name: String, name of model.
        config: Dict, parameter for train.
    """

    model.compile(loss="mse", optimizer="rmsprop", metrics=['mape'])
    # early = EarlyStopping(monitor='val_loss', patience=30, verbose=0, mode='auto')
    hist = model.fit(
        X_train, y_train,
        batch_size=config["batch"],
        epochs=config["epochs"],
        validation_split=0.05)

    model.save('model/' + name + '.h5')
    df = pd.DataFrame.from_dict(hist.history)
    df.to_csv('model/' + name + ' loss.csv', encoding='utf-8', index=False)


def train_seas(models, X_train, y_train, name, config):
    """train
    train the SAEs model.

    # Arguments
        models: List, list of SAE model.
        X_train: ndarray(number, lags), Input data for train.
        y_train: ndarray(number, ), result data for train.
        name: String, name of model.
        config: Dict, parameter for train.
    """

    temp = X_train
    # early = EarlyStopping(monitor='val_loss', patience=30, verbose=0, mode='auto')

    for i in range(len(models) - 1):
        if i > 0:
            p = models[i - 1]
            hidden_layer_model = Model(input=p.input,
                                       output=p.get_layer('hidden').output)
            temp = hidden_layer_model.predict(temp)

        m = models[i]
        m.compile(loss="mse", optimizer="rmsprop", metrics=['mape'])
        m.fit(temp, y_train, batch_size=config["batch"],
              epochs=config["epochs"],
              validation_split=0.05)

        models[i] = m

    saes = models[-1]
    for i in range(len(models) - 1):
        weights = models[i].get_layer('hidden').get_weights()
        saes.get_layer('hidden%d' % (i + 1)).set_weights(weights)

    train_model(saes, X_train, y_train, name, config)

實(shí)驗(yàn)

評(píng)估

在這里使用MAE绰疤、MSE、RMSE稠屠、MAPE峦睡、R2、explained_variance_score幾個(gè)指標(biāo)對(duì)回歸預(yù)測(cè)結(jié)果進(jìn)行評(píng)估权埠。

def MAPE(y_true, y_pred):
    """Mean Absolute Percentage Error
    Calculate the mape.

    # Arguments
        y_true: List/ndarray, ture data.
        y_pred: List/ndarray, predicted data.
    # Returns
        mape: Double, result data for train.
    """

    y = [x for x in y_true if x > 0]
    y_pred = [y_pred[i] for i in range(len(y_true)) if y_true[i] > 0]

    num = len(y_pred)
    sums = 0

    for i in range(num):
        tmp = abs(y[i] - y_pred[i]) / y[i]
        sums += tmp

    mape = sums * (100 / num)

    return mape


def eva_regress(y_true, y_pred):
    """Evaluation
    evaluate the predicted resul.

    # Arguments
        y_true: List/ndarray, ture data.
        y_pred: List/ndarray, predicted data.
    """

    mape = MAPE(y_true, y_pred)
    vs = metrics.explained_variance_score(y_true, y_pred)
    mae = metrics.mean_absolute_error(y_true, y_pred)
    mse = metrics.mean_squared_error(y_true, y_pred)
    r2 = metrics.r2_score(y_true, y_pred)
    print('explained_variance_score:%f' % vs)
    print('mape:%f%%' % mape)
    print('mae:%f' % mae)
    print('mse:%f' % mse)
    print('rmse:%f' % math.sqrt(mse))
    print('r2:%f' % r2)

預(yù)測(cè)

我們使用訓(xùn)練好的模型對(duì)測(cè)試集進(jìn)行預(yù)測(cè)榨了。

def main():
    lstm = load_model('model/lstm.h5')
    gru = load_model('model/gru.h5')
    saes = load_model('model/saes.h5')
    models = [lstm, gru, saes]
    names = ['LSTM', 'GRU', 'SAEs']

    lag = 12
    file1 = 'data/train.csv'
    file2 = 'data/test.csv'
    _, _, X_test, y_test, scaler = process_data(file1, file2, lag)
    y_test = scaler.inverse_transform(y_test)

    y_preds = []
    for name, model in zip(names, models):
        if name == 'SAEs':
            X_test = np.reshape(X_test, (X_test.shape[0], X_test.shape[1]))
        else:
            X_test = np.reshape(X_test, (X_test.shape[0], X_test.shape[1], 1))
        file = 'images/' + name + '.png'
        plot_model(model, to_file=file, show_shapes=True)
        predicted = model.predict(X_test)
        predicted = scaler.inverse_transform(predicted)
        y_preds.append(predicted[:300])
        print(name)
        eva_regress(y_test, predicted)

    plot_results(y_test[: 300], y_preds, names)

預(yù)測(cè)精度對(duì)比如下所示:

Metrics MAE MSE RMSE MAPE R2 Explained variance score
LSTM 7.16 94.20 9.71 21.25% 0.9420 0.9421
GRU 7.18 95.01 9.75 17.42% 0.9415 0.9415
SAEs 7.71 106.46 10.32 25.62% 0.9344 0.9352

預(yù)測(cè)結(jié)果對(duì)比如下所示:

eva.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市攘蔽,隨后出現(xiàn)的幾起案子龙屉,更是在濱河造成了極大的恐慌,老刑警劉巖满俗,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件转捕,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡唆垃,警方通過(guò)查閱死者的電腦和手機(jī)五芝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)辕万,“玉大人枢步,你說(shuō)我怎么就攤上這事〗ツ颍” “怎么了醉途?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)砖茸。 經(jīng)常有香客問(wèn)我隘擎,道長(zhǎng),這世上最難降的妖魔是什么凉夯? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任货葬,我火速辦了婚禮,結(jié)果婚禮上劲够,老公的妹妹穿的比我還像新娘宝惰。我一直安慰自己,他們只是感情好再沧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著尊残,像睡著了一般炒瘸。 火紅的嫁衣襯著肌膚如雪淤堵。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,287評(píng)論 1 301
  • 那天顷扩,我揣著相機(jī)與錄音拐邪,去河邊找鬼。 笑死隘截,一個(gè)胖子當(dāng)著我的面吹牛扎阶,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播婶芭,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼东臀,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了犀农?” 一聲冷哼從身側(cè)響起惰赋,我...
    開(kāi)封第一講書(shū)人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎呵哨,沒(méi)想到半個(gè)月后赁濒,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡孟害,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年拒炎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挨务。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡击你,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出耘子,到底是詐尸還是另有隱情果漾,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布谷誓,位于F島的核電站绒障,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏捍歪。R本人自食惡果不足惜户辱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望糙臼。 院中可真熱鬧庐镐,春花似錦、人聲如沸变逃。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至名眉,卻和暖如春粟矿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背损拢。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工陌粹, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人福压。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓掏秩,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親荆姆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蒙幻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容