1. 程式人生 > >CNTK API文件翻譯(11)——使用LSTM預測時間序列資料(物聯網資料)

CNTK API文件翻譯(11)——使用LSTM預測時間序列資料(物聯網資料)

在上一期我們開發了一個簡單的LSTM神經網路來預測時序資料的值。在本期我們要把這模型用在真實世界的物聯網資料上。作為示例,我們會根據之前幾天觀測到的資料預測太陽能電池板的日產電量。

太陽能發電量預測是一個重要且艱難的問題。太陽能產電量的預測還與天氣預測密切相關。實際上,這個問題分為兩部分,第一部分,我們需要關注太陽能光強度或者其他氣象的變數,另一方面我們需要計算在預測的天氣狀況下太陽能電池板的產電量。通常來說,這種複雜問題的處理經常會涉及到空間和時間尺度的變化,本教程僅僅簡單的通過之前太陽能電池板生成的電量資料預測之後的資料。

目標

通過一塊太陽能電池板以往一天產生的電量,我們需要預測全部太陽能電池板在預測天內產生的電量。我們需要使用在上期開發的基於時間序列預測的LSTM網路模型來根據以往的資料預測太陽能電池板的產電量。
image

我們使用太陽能電池板的歷史資料據來訓練模型,在我們的示例中,我們需要使用之前的資料預測整個太陽能電池板陣列的產電量。我們在最初的兩個資料之後就開始預測,然後與新讀取的資料進行擬合。

在本教程中我們我們會使用上期的LSTM模型,因此與上期類似,有如下幾個部分:

  • 初始化
  • 資料生成
  • LSTM模型構建
  • 模型訓練和評估

初始化

我們先匯入一些庫,定義一些以後會用到的常量。

from matplotlib import pyplot as plt
import math
import numpy as np
import os
import pandas as pd
import
random import time import cntk as C try: from urllib.request import urlretrieve except ImportError: from urllib import urlretrieve

在下面的程式碼中,我們通過檢查在CNTK內部定義的環境變數來選擇正確的裝置(GPU或者CPU)來執行程式碼,如果不檢查的話,會使用CNTK的預設策略來使用最好的裝置(如果GPU可用的話就使用GPU,否則使用CPU)

if 'TEST_DEVICE' in os.environ:
    if os.environ['TEST_DEVICE'
] == 'cpu': C.device.try_set_default_device(C.device.cpu()) else: C.device.try_set_default_device(C.device.gpu(0))

我們設定了兩種執行模式:

  • 快速模式:isFast變數設定成True。這是我們的預設模式,在這個模式下我們會訓練更少的次數,也會使用更少的資料,這個模式保證功能的正確性,但訓練的結果還遠遠達不到可用的要求。
  • 慢速模式:我們建議學習者在學習的時候試試將isFast變數設定成False,這會讓學習者更加了解本教程的內容。

快速模式我們會訓練100個週期,得到的結果會有比較低的精度,不過對於開發來說已經足夠了。這個模型目前比較好的表現需要訓練1000到2000個週期。

isFast = True

# we need around 2000 epochs to see good accuracy. For testing 100 epochs will do.
EPOCHS = 100 if isFast else 2000

我們的太陽能電池板每三十分鐘採集一次資料:

  • solar.current表示當前的產電量,用瓦特表示。
  • solar.total是到當天的目前為止,太陽能電池板的平均功率,用瓦特/小時表示。

我們的預測採用的資料從最初讀取的兩個資料開始。以這些資料為基礎,我們不斷的預測和把預測結果與新的真實值擬合。我們用到的資料採用csv格式,其形式如下:

time,solar.current,solar.total
7am,6.3,1.7
7:30am,44.3,11.4

預處理

在本示例中大部分程式碼都是用來資料預處理的。感謝pandas庫讓資料預處理工作變得非常簡單。

generate_solar_data函式執行了如下任務:

  • 以pandas資料幀的方式讀取CSV資料
  • 格式化資料
  • 資料分組
  • 新增solar.current.max列和solar.total.max列。
  • 生成每天的資料序列

序列生成:所有的序列都會被構成一系列的序列,在這裡再也沒有時間戳的概念,只有序列才是要緊的。

注:如果一天的資料量少於8個,我們會假設當天的資料丟失了,就跳過這天的資料。如果一天的資料多於14條,我們會擷取為14條。

訓練/測試/驗證

我們從使用CNTK讀取CSV檔案開始,資料以一行行組織,通過時間排列,我們需要隨機將這些資料分割成訓練資料集、驗證資料集和測試資料集,但是這樣的分割會讓資料與真實情況不符。因此,我們我們使用如下方式分割資料:把一天的資料讀取進序列,其中八個資料作為訓練資料,一個是驗證資料,一個是測試資料,這就可以讓訓練資料、驗證資料和測試資料分佈在整個時間線上。

def generate_solar_data(input_url, time_steps, normalize=1, val_size=0.1, test_size=0.1):
    """
    generate sequences to feed to rnn based on data frame with solar panel data
    the csv has the format: time ,solar.current, solar.total
     (solar.current is the current output in Watt, solar.total is the total production
      for the day so far in Watt hours)
    """
    # try to find the data file local. If it doesn't exists download it.
    cache_path = os.path.join("data", "iot")
    cache_file = os.path.join(cache_path, "solar.csv")
    if not os.path.exists(cache_path):
        os.makedirs(cache_path)
    if not os.path.exists(cache_file):
        urlretrieve(input_url, cache_file)
        print("downloaded data successfully from ", input_url)
    else:
        print("using cache for ", input_url)

    df = pd.read_csv(cache_file, index_col="time", parse_dates=['time'], dtype=np.float32)

    df["date"] = df.index.date

    # normalize data
    df['solar.current'] /= normalize
    df['solar.total'] /= normalize

    # group by day, find the max for a day and add a new column .max
    grouped = df.groupby(df.index.date).max()
    grouped.columns = ["solar.current.max", "solar.total.max", "date"]

    # merge continuous readings and daily max values into a single frame
    df_merged = pd.merge(df, grouped, right_index=True, on="date")
    df_merged = df_merged[["solar.current", "solar.total",
                           "solar.current.max", "solar.total.max"]]
    # we group by day so we can process a day at a time.
    grouped = df_merged.groupby(df_merged.index.date)
    per_day = []
    for _, group in grouped:
        per_day.append(group)

    # split the dataset into train, validatation and test sets on day boundaries
    val_size = int(len(per_day) * val_size)
    test_size = int(len(per_day) * test_size)
    next_val = 0
    next_test = 0

    result_x = {"train": [], "val": [], "test": []}
    result_y = {"train": [], "val": [], "test": []}    

    # generate sequences a day at a time
    for i, day in enumerate(per_day):
        # if we have less than 8 datapoints for a day we skip over the
        # day assuming something is missing in the raw data
        total = day["solar.total"].values
        if len(total) < 8:
            continue
        if i >= next_val:
            current_set = "val"
            next_val = i + int(len(per_day) / val_size)
        elif i >= next_test:
            current_set = "test"
            next_test = i + int(len(per_day) / test_size)
        else:
            current_set = "train"
        max_total_for_day = np.array(day["solar.total.max"].values[0])
        for j in range(2, len(total)):
            result_x[current_set].append(total[0:j])
            result_y[current_set].append([max_total_for_day])
            if j >= time_steps:
                break
    # make result_y a numpy array
    for ds in ["train", "val", "test"]:
        result_y[ds] = np.array(result_y[ds])
    return result_x, result_y

資料快取

對於常規測試,我們希望使用本地快取的資料。如果快取不能用,我們就需要去下載。

# there are 14 lstm cells, 1 for each possible reading we get per day
TIMESTEPS = 14

# 20000 is the maximum total output in our dataset. We normalize all values with 
# this so our inputs are between 0.0 and 1.0 range.
NORMALIZE = 20000

X, Y = generate_solar_data("https://www.cntk.ai/jup/dat/solar.csv", 
                           TIMESTEPS, normalize=NORMALIZE)

獲取實時資料

next_batch產生下一次用於訓練的資料集。我們在CNTK中使用的變長序列和取樣包都是一系列的numpy陣列,這些陣列都是變長的。

標準的做法是每個訓練週期都隨機抽取資料包,但是我們不這麼幹,為了以後資料視覺化的時候易於理解。

# process batches of 10 days
BATCH_SIZE = TIMESTEPS * 10

def next_batch(x, y, ds):
    """get the next batch for training"""

    def as_batch(data, start, count):
        return data[start:start + count]

    for i in range(0, len(x[ds]), BATCH_SIZE):
        yield as_batch(X[ds], i, BATCH_SIZE), as_batch(Y[ds], i, BATCH_SIZE)

理解資料格式

現在你可以看到我們輸進LSTM神經網路的資料了。

X['train'][0:3]

輸出:

[array([ 0.       ,  0.0006985], dtype=float32),
 array([ 0.       ,  0.0006985,  0.0033175], dtype=float32),
 array([ 0.       ,  0.0006985,  0.0033175,  0.010375 ], dtype=float32)]
Y['train'][0:3]

輸出

array([[ 0.23899999],
       [ 0.23899999],
       [ 0.23899999]], dtype=float32)

LSTM神經網路初始化

與最多14個輸入資料相對應,我們的模型有14個LSTM單元,每個單元代表當天的每個輸入資料點。由於輸入的資料在8到14之間變動,我們就可以利用CNTK可變長序列的優勢,而不用專門去填充空白的輸入單元。

神經網路的輸出值是某天的輸出電量值,給定的每個序列具有一樣的總輸出電量。打個比方:

1.7,11.4 -> 10300
1.7,11.4,67.5 -> 10300
1.7,11.4,67.5,250.5 ... -> 10300
1.7,11.4,67.5,250.5,573.5 -> 10300

LSTM的輸出值作為全連線網路層的輸入值,當然其中會被隨機丟掉百分之二十,來避免過度擬合。全連線網路層的輸出值就是我們這個模型的預測值了。

我們的LSTM模型設計如下:
image

下面的程式碼就是對上圖的實現:

def create_model(x):
    """Create the model for time series prediction"""
    with C.layers.default_options(initial_state = 0.1):
        m = C.layers.Recurrence(C.layers.LSTM(TIMESTEPS))(x)
        m = C.sequence.last(m)
        m = C.layers.Dropout(0.2)(m)
        m = C.layers.Dense(1)(m)
        return m

訓練

在我們訓練之前我們需要繫結輸入資料,選定訓練器。在本示例中我們使用adam訓練器,squared_error作為成本函式。

# input sequences
x = C.sequence.input_variable(1)

# create the model
z = create_model(x)

# expected output (label), also the dynamic axes of the model output
# is specified as the model of the label input
l = C.input_variable(1, dynamic_axes=z.dynamic_axes, name="y")

# the learning rate
learning_rate = 0.005
lr_schedule = C.learning_rate_schedule(learning_rate, C.UnitType.minibatch)

# loss function
loss = C.squared_error(z, l)

# use squared error to determine error for now
error = C.squared_error(z, l)

# use adam optimizer
momentum_time_constant = C.momentum_as_time_constant_schedule(BATCH_SIZE / -math.log(0.9)) 
learner = C.fsadagrad(z.parameters, 
                      lr = lr_schedule, 
                      momentum = momentum_time_constant)
trainer = C.Trainer(z, (loss, error), [learner])


# training
loss_summary = []

start = time.time()
for epoch in range(0, EPOCHS):
    for x_batch, l_batch in next_batch(X, Y, "train"):
        trainer.train_minibatch({x: x_batch, l: l_batch})

    if epoch % (EPOCHS / 10) == 0:
        training_loss = trainer.previous_minibatch_loss_average
        loss_summary.append(training_loss)
        print("epoch: {}, loss: {:.4f}".format(epoch, training_loss))

print("Training took {:.1f} sec".format(time.time() - start))

結果:

epoch: 0, loss: 0.0966
epoch: 10, loss: 0.0305
epoch: 20, loss: 0.0208
epoch: 30, loss: 0.0096
epoch: 40, loss: 0.0088
epoch: 50, loss: 0.0072
epoch: 60, loss: 0.0071
epoch: 70, loss: 0.0075
epoch: 80, loss: 0.0082
epoch: 90, loss: 0.0082
Training took 134.4 sec

然後我們測試和驗證。我們使用均方誤差成本函式可能稍微有點簡單,有個辦法,我們可以計算在誤差允許範圍內的比率。

# validate
def get_mse(X,Y,labeltxt):
    result = 0.0
    for x1, y1 in next_batch(X, Y, labeltxt):
        eval_error = trainer.test_minibatch({x : x1, l : y1})
        result += eval_error
    return result/len(X[labeltxt])

# Print the train and validation errors
for labeltxt in ["train", "val"]:
    print("mse for {}: {:.6f}".format(labeltxt, get_mse(X, Y, labeltxt)))

# Print the test error
labeltxt = "test"
print("mse for {}: {:.6f}".format(labeltxt, get_mse(X, Y, labeltxt)))

視覺化預測結果

我們的模型訓練狀況量好,因為訓練、測試和驗證的誤差值都在一個可控的範圍內。預測的時序資料能夠很好的可視化出來,讓我們看看實際和預測的對比。

# predict
f, a = plt.subplots(2, 1, figsize=(12, 8))
for j, ds in enumerate(["val", "test"]):
    results = []
    for x_batch, _ in next_batch(X, Y, ds):
        pred = z.eval({x: x_batch})
        results.extend(pred[:, 0])
    # because we normalized the input data we need to multiply the prediction
    # with SCALER to get the real values.
    a[j].plot((Y[ds] * NORMALIZE).flatten(), label=ds + ' raw');
    a[j].plot(np.array(results) * NORMALIZE, label=ds + ' pred');
    a[j].legend();

image

如果訓練兩千個週期,資料會非常好看。


歡迎掃碼關注我的微信公眾號獲取最新文章
image

相關推薦

CNTK API翻譯(11)——使用LSTM預測時間序列資料聯網資料

在上一期我們開發了一個簡單的LSTM神經網路來預測時序資料的值。在本期我們要把這模型用在真實世界的物聯網資料上。作為示例,我們會根據之前幾天觀測到的資料預測太陽能電池板的日產電量。 太陽能發電量預測是一個重要且艱難的問題。太陽能產電量的預測還與天氣預測密切相關

CNTK API翻譯(10)——使用LSTM預測時間序列資料

本篇教程展示如何用CNTK構建LSTM來進行時間序列資料的數值預測。 目標 我們使用一個連續函式的模擬資料集(本例使用正弦曲線)。對於函式y=sin(t),我們使用符合這個函式的N個值來預測之後的M個值。 在本教程中我們將使用基於LSTM的模型。L

CNTK API翻譯(19)——藝術風格轉變

本教程展示瞭如何將一張圖片的風格轉換成另外一種。這讓我們可以將一張原始照片渲染成世界名畫的風格。 與建立一個好看的圖片不同,在本教程中你講學習如何在CNTK中載入一個已經訓練好的VGG模型,如何基於輸入變數獲取對應的梯度,以及如何在不使用CNTK的時候使用梯度

CNTK API翻譯(9)——使用自編碼器壓縮MNIST資料

在本期教程之前需要先完成第四期教程。 介紹 本教程介紹自編碼器的基礎。自編碼器是一種用於高效編碼的無監督學習人工神經網路,換句話說,自編碼器用於通過機器學習學來的演算法而不是人寫的演算法進行有損資料壓縮。由此而來,使用自編碼器編碼的目的是訓練出一套資料表

CNTK API翻譯(17)——多對多神經網路處理文字資料1

(本期教程需要翻譯的內容實在是太多了,將其分割成兩期,本期主要講理論和模型建立,下期主要講訓練、測試、優化等) 背景和簡介 本教程將帶你過一遍多對多神經網路基礎,以及如何在CNTK中實現它。具體來說,我們將實現一個多對多模型用來實現字音轉換。我們首先會介

CNTK API翻譯(25)——後記

這篇不是翻譯,是我自己寫的後記,CNTK API文件翻系列譯完結。 CNTK是微軟的一個深度學習套件,他的存在主要是可以讓開發人員不用知道里面的各種演算法的細節,就能使用訓練深度神經網路模型。他提供了已經封裝好的元件來給我們使用:你不需要知道隨機梯度下降下降演

CNTK API翻譯(18)——多對多神經網路處理文字資料2

(本期教程需要翻譯的內容實在是太多了,將其分割成兩期,上期主要講理論和模型建立,本期主要講訓練、測試、優化等) 訓練 在我們開始訓練之前,我們將定義訓練封裝器、貪婪解碼封裝器以及用於訓練模型的準則函式。首先是訓練封裝器。 def create_mo

CNTK API翻譯(23)——使用CTC標準訓練聲學模型

本教程假定所有讀者都完成了前10期教程,並且對聲學建模的資料形式有基礎的瞭解。本教程介紹了CNTK種可以用於訓練以CTC(Connectionist Temporal Classification)訓練準則為例的語音識別深度神經網路的模組。 介紹 CNT

CNTK API翻譯(20)——GAN處理MSIST資料基礎

完成本期教程需要完成本系列的第四篇教程。 介紹 生成模型在深度學習的半監督或者非監督學習領域引起了廣泛的專注,這些領域傳統上都是使用判別模型的。生成模型的思想是線收集某個研究領域巨量的資料,然後訓練得到一個可以生成這樣的資料集的模型。這是一個需要大量訓練

CNTK API翻譯(3)——前饋神經網路

這個教程的目的是為了讓你熟悉使用CNTK元件來進行分類任務,如果你看了本系列的邏輯迴歸部分或者熟悉機器學習,可以跳過介紹部分。 介紹(見上期,本期略) 前饋神經網路模型 本次使用的資料集和上期邏輯迴歸教程使用的資料集一樣,不過這期的模型會結合多個邏

CNTK API翻譯(8)——使用Pandas和金融資料進行時序資料基本分析

本期將帶來使用CNTK處理時間序列資料的教程。本教程中會展示怎樣為深度學習演算法準備時間資料、訓練神經網路和評估神經網路。具體來說,我們會探究預測交易性開放式指數基金(Exchange-traded Funds,EFI)的分類是否靠譜,進而通過這種簡單的分類來決

CNTK API翻譯(2)——邏輯迴歸

這篇教程的目標人群是機器學習和CNTK的新手。在這篇教程中,你將訓練一個簡單但是強大的機器學習模型,這個模型被廣泛用於各個行業的應用中。這個訓練可以使用CNTK庫,通過擴充計算資源(CPU、GPU)來推廣到大量的資料集。 介紹 問題: 一個腫瘤醫院提供了

CNTK API翻譯(15)——自然語言理解

本教程展示瞭如何實現一個遞迴神經網路來處理文字,為航空出行資訊服務(ATIS)資料提供分詞標記任務(將不同的詞分到各自的類中,分類由訓練資料集提供)。我們從文字線型降維開始,然後訓練和使用LSTM神經網路。這將被擴充套件到相鄰的單詞並且雙向執行。最後我們將完成一

CNTK API翻譯(12)——CNTK進階

這篇教程展示了CNTK中一些比較高階的特性,目標讀者是完成了之前教程或者是使用過其他機器學習元件的人。如果你是完完全全的新手,請先看我們之前的十多期教程。 歡迎來到CNTK。深度神經網路正在重新定義計算機程式設計。在指令式程式設計、函式式變成和申明式變成之外,

RabbitMQ開發庫的完整API(翻譯)

背景 譯文連結 我的譯文 概述 Connections and Channels 連線到一個代理 使用 Exchanges and Queues佇列 釋出訊息Publish

java API翻譯

 概述  軟體包  類  使用  樹  已過時  索引  幫助  JavaTM 2 Platform Standard Ed. 6  上一個   下一個 框架    無框架    所有類 JavaTM 2 Platform Standard Edition

Django Rest 與 React(Django2.1 + coverage測試 + xadmin + 線上api)-翻譯實踐強化版

原文: www.valentinog.com/blog/tutori… 翻譯版實踐教程: Django Rest 與 React(Django2.1 加 一點小測試 加一點譯者的小額外功能) 最終構建了一個有後臺管理 + 提供api服務 + Mysql資料庫 + 線上api文件的Lead系統。

Pulsar官方翻譯-入門必看-概念和架構-概覽Pulsar Overview

官網原文標題《Concepts and Architecture--Pulsar Overview》 翻譯時間:2018-09-28 譯者:本文介紹了Pulsar的起源和現狀,以及主要特性。 後續閱讀:《Messaging Concepts》 譯者序言: 由

Pulsar官方翻譯-概念和架構-Pulsar客戶端Pulsar Clients

本篇翻譯轉自Zongyang在crowdin apache pulsar專案中的翻譯,由於已經完成翻譯,我直接轉載,不再翻譯。 ------------------------------------------ Pulsar 客戶端 Pulsar向用戶暴露原生的Jav

maven的pom.xml配置中常用的配置標簽解析2018-03-13

pid scope nic beta class 公測 manage gin release 來自:https://www.cnblogs.com/Nick-Hu/p/7288198.html 拿過來記錄下 <project xmlns="http://maven.