keras構建LSTM模型,預測帶高度的經緯度位置

原始時間序列數據如下所示,我們將緯度、經度、高度作爲輸入

其軌跡經緯度如下圖所示:

用keras創建一個三層的LSTM網絡訓練模型如下圖所示:

import numpy as np
from keras.layers.core import Dense, Activation, Dropout
from keras.layers import LSTM
from keras.models import Sequential, load_model
from keras.callbacks import Callback
import keras.backend.tensorflow_backend as KTF
import tensorflow as tf
import pandas as pd
import os
import  keras.callbacks
import matplotlib.pyplot as plt

#設定爲自增長
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
session = tf.Session(config=config)
KTF.set_session(session)


def trainModel(train_X, train_Y):
    '''
    trainX,trainY: 訓練LSTM模型所需要的數據
    '''
    model = Sequential()  # 定義一個堆疊的順序模型
    model.add(LSTM(
        240,
        input_shape=(train_X.shape[1], train_X.shape[2]),
        return_sequences=True)) 
    model.add(Dropout(0.3))

    model.add(LSTM(
        240,
        return_sequences=True))  
    model.add(Dropout(0.3))

    model.add(LSTM(
        240,
        return_sequences=False))  # 返回維度爲 240 的單個向量
    model.add(Dropout(0.3))

    model.add(Dense(
        train_Y.shape[1]))
    model.add(Activation("relu"))

    model.compile(loss='mse', optimizer='adam', metrics=['acc'])  # 配置模型學習過程

    model.fit(train_X, train_Y, epochs=100, batch_size=64, verbose=1, validation_data=(test_X, test_Y))
    model.summary()

    return model

if __name__ == "__main__":
    train_num = 6
    per_num = 1
    # set_range = False
    set_range = True
    series_idx = ['lat', 'lon', 'altitude']
    # 讀入時間序列的文件數據
    data = pd.read_csv('20081213052002.txt', sep=',').loc[:, series_idx].values
    print("樣本數:{0},維度:{1}".format(data.shape[0], data.shape[1]))
    # print(data)

    # 畫樣本數據庫
    plt.scatter(data[:, 1], data[:, 0], c='b', marker='o', label='traj_A')
    plt.legend(loc='upper left')
    plt.grid()
    plt.show()

    #歸一化
    data, normalize = NormalizeMult(data, set_range)
    # print(normalize)

    #生成訓練數據
    train_X, train_Y, test_X, test_Y = create_dataset(data, train_num, per_num)
    print("x\n", train_X.shape)
    print("y\n", train_Y.shape)


    # 訓練模型
    model = trainModel(train_X, train_Y)
    loss, acc = model.evaluate(train_X, train_Y, verbose=2)
    print('Loss : {}, Accuracy: {}'.format(loss, acc * 100))

    # 保存模型
    np.save("./traj_model_trueNorm.npy", normalize)
    model.save("./traj_model_240_3layers_altitude.h5")

模型訓練結果如下:

 

創建LSTM網絡預測模型:

import numpy as np
from keras.layers.core import Dense, Activation, Dropout
from keras.layers import LSTM
from keras.models import Sequential, load_model
from keras.callbacks import Callback
import keras.backend.tensorflow_backend as KTF
import tensorflow as tf
import  pandas as pd
import  os
import  keras.callbacks
import matplotlib.pyplot as plt
import copy

#設定爲自增長
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
session = tf.Session(config=config)
KTF.set_session(session)

def rmse(predictions, targets):
    return np.sqrt(((predictions - targets) ** 2).mean())
def mse(predictions, targets):
    return ((predictions - targets) ** 2).mean()

def reshape_y_hat(y_hat,dim):
    re_y = []
    i = 0
    while i < len(y_hat):
        tmp = []
        for j in range(dim):
            tmp.append(y_hat[i+j])
        i = i + dim
        re_y.append(tmp)
    re_y = np.array(re_y, dtype='float64')
    return re_y

#多維反歸一化
def FNormalizeMult(data,normalize):

    data = np.array(data, dtype='float64')
    #列
    for i in range(0, data.shape[1]):
        listlow = normalize[i, 0]
        listhigh = normalize[i, 1]
        delta = listhigh - listlow
        print("listlow, listhigh, delta", listlow, listhigh, delta)
        #行
        if delta != 0:
            for j in range(0, data.shape[0]):
                data[j, i] = data[j, i]*delta + listlow

    return data

#使用訓練數據的歸一化
def NormalizeMultUseData(data,normalize):

    for i in range(0, data.shape[1]):

        listlow = normalize[i, 0]
        listhigh = normalize[i, 1]
        delta = listhigh - listlow

        if delta != 0:
            for j in range(0, data.shape[0]):
                data[j, i] = (data[j, i] - listlow)/delta

    return data


from math import sin, asin, cos, radians, fabs, sqrt

EARTH_RADIUS = 6371  # 地球平均半徑,6371km

# 計算兩個經緯度之間的直線距離
def hav(theta):
    s = sin(theta / 2)
    return s * s
def get_distance_hav(lat0, lng0, lat1, lng1):
    # "用haversine公式計算球面兩點間的距離。"
    # 經緯度轉換成弧度
    lat0 = radians(lat0)
    lat1 = radians(lat1)
    lng0 = radians(lng0)
    lng1 = radians(lng1)

    dlng = fabs(lng0 - lng1)
    dlat = fabs(lat0 - lat1)
    h = hav(dlat) + cos(lat0) * cos(lat1) * hav(dlng)
    distance = 2 * EARTH_RADIUS * asin(sqrt(h))
    return distance

if __name__ == '__main__':
    test_num = 6
    per_num = 1
    series_idx = ['lat', 'lon', 'altitude']
    test_move_loc = 0
    data_all = pd.read_csv('20081213052002.txt', sep=',')
    data_all = data_all.loc[np.arange(len(data_all)-test_num-per_num-test_move_loc, len(data_all)-test_move_loc).tolist(), series_idx].values
    # print(data_all)
    data_all.dtype = 'float64'

    data = copy.deepcopy(data_all[:-per_num, :])
    y = data_all[-per_num:, :]
  
    # #歸一化
    normalize = np.load("./traj_model_trueNorm.npy")
    data = NormalizeMultUseData(data, normalize)

    model = load_model("./traj_model_120.h5")
    test_X = data.reshape(1, data.shape[0], data.shape[1])
    y_hat = model.predict(test_X)
    y_hat = y_hat.reshape(y_hat.shape[1])
    y_hat = reshape_y_hat(y_hat, y.shape[1])

    #反歸一化
    y_hat = FNormalizeMult(y_hat, normalize)
    print("predict: {0}\ntrue:{1}".format(y_hat, y))
    # print('預測均方誤差:', mse(y_hat, y))
    print('預測均方誤差:', mse(y_hat[-1, :], y[-1, :]))
    # print('預測直線距離:{:.4f} KM'.format(get_distance_hav(y_hat[0, 0], y_hat[0, 1], y[0, 0], y[0, 1])))
    print('預測直線距離:{:.4f} KM'.format(get_distance_hav(y_hat[-1, 0], y_hat[-1, 1], y[-1, 0], y[-1, 1])))
    print('預測高度差:{:.4f} M'.format((y_hat[-1, 2]-y[-1, 2]) * 0.3047999995367))  #  1 feet = 0.3047999995367 m

   
    # 畫測試樣本數據庫
    p1 = plt.scatter(y_hat[:, 1], y_hat[:, 0], c='r', marker='o', label='pre')
    p2 = plt.scatter(y[:, 1], y[:, 0], c='g', marker='o', label='pre_true')
    plt.legend(loc='upper left')
    plt.grid()
    plt.show()

預測結果如下:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章