返回文章列表

TensorFlow PyTorch 股票預測效能比較

本文比較 TensorFlow 與 PyTorch 應用於特斯拉股價預測的效能差異,分析訓練損失、測試損失和 R2 分數等指標。結果顯示,儘管 TensorFlow 在測試損失上表現更佳,但兩者在 R2

機器學習 深度學習

深度學習框架 TensorFlow 與 PyTorch 在模型訓練的效能表現上各有千秋。本文以特斯拉股價預測為例,比較兩者在訓練損失、測試損失及 R2 分數上的差異。實驗結果顯示,PyTorch 初期訓練損失較高,但最終能收斂至與 TensorFlow 相近的程度。雖然 TensorFlow 的測試損失較低,但兩者的 R2 分數幾乎相同,皆接近 0.998,顯示兩者皆能有效預測股價走勢。進一步分析發現,TensorFlow 採用靜態計算圖,最佳化效率高,適合生產環境,但開發彈性較低。PyTorch 則使用動態計算圖,方便實驗和除錯,更適合研究場景。文章也提供完整的 TensorFlow 股票價格預測模型程式碼,包含資料預處理、模型建構、訓練與評估,並提供 environment.yml 檔案以利讀者快速復現實驗環境。

TensorFlow 與 PyTorch 效能比較分析

在前一章節中,我們使用 PyTorch 進行了特斯拉股價預測模型的訓練,而在本章節中,我們則採用了 TensorFlow 來實作相同的任務。透過比較這兩個框架在訓練損失、測試損失和 R2 分數上的表現,我們可以深入瞭解它們在股價預測任務中的效能差異。

訓練損失比較

下表展示了 PyTorch 和 TensorFlow 在前十個 epoch 以及第 100 個 epoch 的訓練損失:

EpochPyTorchTensorFlow
1/10048,53341,731
2/10040,96940,362
3/10026,66339,658
4/10013,86533,450
5/1003,02619,520
6/1001,6835,492
7/1001,0772,532
8/1004751,984
9/1001,1951,657
10/1001,3621,231
100/1001114

根據這些資料,我們可以得出以下結論:

  • PyTorch 的初始訓練損失通常高於 TensorFlow。
  • 兩個框架的訓練損失都隨著 epoch 的增加而持續下降,顯示出有效的最佳化過程。
  • PyTorch 和 TensorFlow 在損失減少的趨勢上相似,最終都收斂到較低的值。
  • 在某些 epoch 中,兩個框架之間的損失值存在微小差異,但整體趨勢是相似的。
  • 在訓練的最後階段,兩個框架都達到了較低的訓練損失,表明模型已經有效地收斂。

測試損失與 R2 分數比較

下表比較了 PyTorch 和 TensorFlow 在測試損失和 R2 分數上的表現:

MetricPyTorchTensorFlow
測試損失20.5412.11
R2 分數0.9980.998

結果顯示,PyTorch 的測試損失為 20.54,而 TensorFlow 的測試損失則為 12.11,明顯低於 PyTorch。然而,兩個模型的 R2 分數均約為 0.998,顯示出極高的解釋能力和預測準確度,能夠很好地捕捉測試資料的變異。

儘管測試損失存在差異,但相似的 R2 分數表明兩個框架所建立的模型在預測特斯拉股價方面具有相似的效能。

TensorFlow 與 PyTorch 的實務差異

雖然本比較是在相同的資料集和模型架構下進行的,但 TensorFlow 和 PyTorch 在實務應用上仍存在一些差異。TensorFlow 使用靜態計算圖,需要預先定義模型的結構,這使得它能夠針對效能進行最佳化,特別適合於生產環境中對效率有嚴格要求的場景。然而,這種靜態特性使得開發過程相對僵化,因為任何對模型的修改都需要重新定義計算圖,這在研究環境中可能會減慢模型迭代的速度。

相對地,PyTorch 的動態計算圖允許實時修改模型,提供了更靈活和直觀的開發體驗。這種動態特性使得 PyTorch 在實驗階段具有明顯優勢,尤其是在需要頻繁調整和測試模型的情況下。動態圖還簡化了除錯過程,允許開發者在執行時檢查和修改模型的行為,從而加快迭代和問題解決的速度。

此外,兩個框架的易用性和生態系統也扮演著重要的角色。TensorFlow 自 TensorFlow 2.0 以來,透過整合 Keras 作為其高階 API,變得越來越易用。其豐富的生態系統,包括用於佈署的 TensorFlow Serving,使其成為從開發到生產的完整機器學習流程中的強大選擇。

相比之下,PyTorch 簡潔的介面以及與 NumPy 等 Python 函式庫的無縫整合,為開發者提供了更直觀的使用體驗,尤其是對於剛接觸深度學習的新手。其生態系統正在快速發展,像 PyTorch Lightning 和 TorchServe 這樣的工具進一步擴充套件了其功能,使其在研究領域仍然具有顯著優勢。

圖表分析:實際值 vs. 預測值
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333

title TensorFlow 與 PyTorch 的實務差異

rectangle "x-axis" as node1
rectangle "y-axis" as node2
rectangle "理想預測" as node3

node1 --> node2
node2 --> node3

@enduml

此圖示說明瞭模型的預測值與實際值之間的關係。透過觀察散佈圖中資料點沿對角虛線的分佈,可以評估模型的預測準確度。資料點緊密圍繞對角線,表明模型具有良好的預測能力。

程式碼範例:TensorFlow 與 PyTorch 的比較

# TensorFlow 版本
import tensorflow as tf

model = tf.keras.models.Sequential([...])
model.compile(optimizer='adam', loss='mean_squared_error')
model.fit(x_train, y_train, epochs=100)

# PyTorch 版本
import torch
import torch.nn as nn

class Model(nn.Module):
    def __init__(self):
        super(Model, self).__init__()
        self.layers = nn.Sequential([...])

    def forward(self, x):
        return self.layers(x)

model = Model()
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
for epoch in range(100):
    optimizer.zero_grad()
    outputs = model(inputs)
    loss = criterion(outputs, labels)
    loss.backward()
    optimizer.step()

程式碼解密:

  1. TensorFlow 版本:使用 tf.keras.models.Sequential 定義模型,並使用 compile 方法設定最佳化器和損失函式。透過 fit 方法進行模型訓練。
  2. PyTorch 版本:定義一個繼承自 nn.Module 的模型類別,並在 forward 方法中定義前向傳播過程。使用 nn.MSELoss() 定義損失函式,並使用 torch.optim.Adam 設定最佳化器。在訓練迴圈中,清零梯度、進行前向傳播、計算損失、反向傳播並更新引數。
  3. 比較:兩個框架在實作相同任務時展現出不同的風格,TensorFlow 更適合快速原型設計,而 PyTorch 提供更大的靈活性。

結合所有元素:建立完整的TensorFlow迴歸模型

本章節將整合本章所探討的多樣化程式碼元素,以開發一個完整的程式碼函式庫。同時,我們將提供更多關於模型設計選擇的背景資訊,幫助讀者瞭解為何選擇特定的層和啟用函式。此外,我們還會提供一個environment.yml檔案,以便讀者輕鬆複製相同的環境。

層與啟用函式的選擇

層的選擇

模型使用了一系列具有64、32和16個神經元的密集層。這種逐漸減少神經元數量的設計幫助模型在初始層捕捉複雜模式,而後續層則專注於精煉和減少資料複雜度。這種設計透過逐漸縮小模型的焦點,有助於防止過度擬合。

啟用函式—ReLU

ReLU(修正線性單元)被用作隱藏層的啟用函式,因為它能夠有效地處理非線性資料並避免梯度消失的問題。ReLU能夠加速訓練過程中的收斂速度,使其成為許多深度學習模型(尤其是涉及股票價格等複雜資料的任務)的首選。

輸出層

輸出層由一個單一神經元組成,沒有啟用函式(線性)。這種選擇在迴歸模型中很常見,因為目標是預測一個連續值。線性啟用確保輸出可以跨越所有可能的值,這對於準確預測股票價格是必要的。

environment.yml檔案

此檔案指定了專案中使用的Python套件版本,讓讀者能夠輕鬆地重現相同的設定。

name: tsla_regression
channels:
- defaults
dependencies:
- python=3.12.3
- numpy=1.26.4
- tensorflow=2.17.0
- pyspark=3.5.2
- scikit-learn=1.5.1
- matplotlib=3.9.2

TensorFlow迴歸程式碼

以下是建立、訓練和評估TensorFlow迴歸模型的程式碼,用於預測Tesla股票價格:

import logging
import numpy as np
import tensorflow as tf
from pyspark.sql import SparkSession
from pyspark.ml.feature import VectorAssembler, StandardScaler
from sklearn.metrics import r2_score
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
import matplotlib.pyplot as plt

class TSLARegressor:
    """
    用於TSLA股票價格迴歸的類別。
    """
    def __init__(self):
        """
        初始化TSLARegressor物件。
        """
        self.logger = logging.getLogger(__name__)
        self.spark = SparkSession.builder.appName("TSLA_Regression").getOrCreate()
        self.input_shape = None
        self.model = None

    def preprocess_data(self, file_path, feature_cols=['Open', 'High', 'Low', 'Volume'], train_ratio=0.8, seed=42):
        """
        預處理資料。
        
        引數:
        - file_path (str):CSV檔案的路徑。
        - feature_cols (list):特徵欄位的列表。
        - train_ratio (float):訓練資料的比例。
        - seed (int):用於分割資料的隨機種子。
        
        傳回:
        - tuple:包含訓練和測試DataFrame的元組。
        """
        df = self.spark.read.csv(file_path, header=True, inferSchema=True)
        assembler = VectorAssembler(inputCols=feature_cols, outputCol='features')
        df = assembler.transform(df)
        scaler = StandardScaler(inputCol='features', outputCol='scaled_features', withMean=True, withStd=True)
        scaler_model = scaler.fit(df)
        df = scaler_model.transform(df)
        train_df, test_df = df.randomSplit([train_ratio, 1-train_ratio], seed=seed)
        return train_df, test_df

    def convert_to_numpy(self, train_df, test_df):
        """
        將Spark DataFrame轉換為numpy陣列。
        
        引數:
        - train_df (DataFrame):包含訓練資料的Spark DataFrame。
        - test_df (DataFrame):包含測試資料的Spark DataFrame。
        
        傳回:
        - tuple:包含訓練和測試特徵及標籤的numpy陣列的元組。
        """
        train_features = np.array(train_df.select('scaled_features').rdd.map(lambda x: x.scaled_features.toArray()).collect())
        train_labels = np.array(train_df.select('Close').rdd.map(lambda x: x.Close).collect())
        test_features = np.array(test_df.select('scaled_features').rdd.map(lambda x: x.scaled_features.toArray()).collect())
        test_labels = np.array(test_df.select('Close').rdd.map(lambda x: x.Close).collect())
        return train_features, train_labels, test_features, test_labels

    def create_and_train_model(self, train_features, train_labels, epochs=100, batch_size=32):
        """
        建立和訓練神經網路模型。
        
        引數:
        - train_features (ndarray):訓練特徵。
        - train_labels (ndarray):訓練標籤。
        - epochs (int):訓練的輪數。
        - batch_size (int):訓練的批次大小。
        
        傳回:
        - None
        """
        self.input_shape = (train_features.shape[1],)
        self.model = Sequential([
            Dense(64, activation='relu', input_shape=self.input_shape),
            Dense(32, activation='relu'),
            Dense(16, activation='relu'),
            Dense(1)
        ])
        self.model.compile(optimizer='adam', loss='mse')
        self.model.fit(train_features, train_labels, epochs=epochs, batch_size=batch_size)

    def evaluate_model(self, test_features, test_labels):
        """
        評估訓練好的模型。
        
        引數:
        - test_features (ndarray):測試特徵。
        - test_labels (ndarray):測試標籤。
        
        傳回:
        - float:測試損失。
        """
        test_loss = self.model.evaluate(test_features, test_labels)
        return test_loss

    def predict_and_evaluate(self, test_features, test_labels):
        """
        預測和評估神經網路模型。
        
        引數:
        - test_features (ndarray):測試特徵。
        - test_labels (ndarray):測試標籤。
        
        傳回:
        - float:R2分數。
        """
        test_predictions = self.model.predict(test_features)
        r2_score_value = r2_score(test_labels, test_predictions)
        return r2_score_value

    def plot_actual_vs_predicted(self, test_features, test_labels):
        """
       繪製實際值與預測值。
        
       引數:
       - test_features (ndarray):測試特徵。
       - test_labels (ndarray):測試標籤。
        
       傳回:
       - None
       """
       test_predictions = self.model.predict(test_features)
       print("Actual Predicted")
       for actual, predicted in zip(test_labels, test_predictions):
           print(f"{actual} {predicted}")

程式碼解密:

  1. 類別定義TSLARegressor類別封裝了與TSLA股票價格迴歸相關的所有功能,包括資料預處理、模型建立、訓練、評估和預測等方法。每個方法都有清晰的檔案字串,描述其功能、引數和傳回值。

  2. 資料預處理preprocess_data方法使用Spark進行資料讀取、特徵彙編和標準化。標準化是必要的,因為它可以提高模型的穩定性和收斂速度。

  3. 轉換為numpy陣列convert_to_numpy方法將Spark DataFrame轉換為numpy陣列,以便於TensorFlow模型的使用。

  4. 模型建立和訓練create_and_train_model方法定義了一個具有多個密集層的Sequential模型,並使用Adam最佳化器和均方誤差(MSE)作為損失函式進行編譯。然後,使用提供的訓練資料對模型進行訓練。

  5. 模型評估evaluate_model方法使用測試資料評估模型的效能,傳回測試損失。predict_and_evaluate方法則進行預測並計算R2分數,以評估模型的預測能力。

  6. 繪製實際值與預測值:雖然原始程式碼片段中這個方法的實作不完整,但在實際應用中,這個方法應該用於視覺化模型的預測結果與實際值的對比,幫助直觀地評估模型效能。

  7. 環境組態:透過environment.yml檔案,確保所有依賴項的版本一致性,使得環境組態變得簡單且可重複。

這段程式碼展示瞭如何使用TensorFlow和Spark來建立一個股票價格預測模型,從資料預處理到模型評估的全過程。透過這種方式,開發者可以根據實際需求調整模型架構和引數,以最佳化預測效能。