發佈日期:

如何從預先訓練的模型中提取特徵

如何從一個已經訓練好的模型(預訓練模型)中,提取出我們感興趣的資料特徵。

什麼是預訓練模型?

預訓練模型就像是一個已經受過良好教育的人,他對很多事情都有基本的認識。在機器學習中,預訓練模型是指在一個非常大且多樣的資料集上訓練過的模型。例如,一個圖像識別的預訓練模型可能已經看過數百萬張圖片,因此它對各種物體、場景都有很深的理解。

我們可以將整個預先訓練的模型看作是一個特徵提取器。 將輸入數據丟入預先訓練的模型中,然後使用模型的最後一層輸出 (通常是分類層) 作為特徵。

為什麼要提取特徵?

  • 加速模型訓練: 如果我們有一個新的任務,但資料量不夠大,直接訓練一個新的模型可能會效果不佳。這時,我們可以利用預訓練模型提取出來的特徵,作為新模型的輸入。因為這些特徵已經包含了大量有用的資訊,所以新模型只需要學習如何將這些特徵組合起來,就能達到不錯的效果。
  • 理解模型: 通過分析提取出來的特徵,我們可以更好地了解模型是如何工作的,哪些特徵對模型的預測結果影響最大。
  • 轉移學習: 將一個模型在一個任務上學到的知識,應用到另一個相關的任務上。

具體範例

使用 ImageNet 預訓練模型進行圖像分類

情境: 假設我們有一個小型的新數據集,包含貓、狗和馬的圖片,我們希望訓練一個模型來區分這三種動物。我們可以利用 ImageNet 預訓練模型來加速這個過程。ImageNet 是一个非常大的圖像數據集,包含數百萬張圖片和數千個類別。

步驟:

  1. 選擇預訓練模型: 我們選擇一個在 ImageNet 上訓練好的 CNN 模型,例如 ResNet50 或 VGG16。這些模型已經學習到了圖像中常見的低層特徵(如邊緣、紋理)和高層特徵(如物體的形狀、位置)。
  2. 移除最後一層: 這些模型的最後一層通常是一個全連接層,用於輸出 ImageNet 中的所有類別。由於我們的任務只有三個類別,所以我們將這一層移除。
  3. 添加新的分類器: 在移除的層之後,我們添加一個新的全連接層,輸出節點數為 3(貓、狗、馬),並初始化隨機權重。
  4. 固定前面的層: 為了保留預訓練模型學到的豐富特徵,我們可以將前面的層的權重固定住,只訓練新添加的分類器。
  5. 訓練模型: 使用我們的小型数据集對模型進行訓練。由於前面的層已經學習到了很多有用的特徵,因此我們只需要訓練很少的迭代次數就能達到不錯的效果。

為什麼這麼做?

  • ImageNet 預訓練模型已經學習到了圖像中非常豐富的通用特徵,例如邊緣、紋理、物體的形狀等。這些特徵對於我們的任務(貓、狗、馬的分類)也是非常有用的。
  • 固定前面的層可以大大減少需要訓練的參數數量,加速訓練過程,並且可以防止過度擬合。
  • 只訓練最後一層可以讓我們快速適應新的任務,而不需要從頭開始訓練一個全新的模型。

提取特徵的常見應用場景

  • 小數據集的分類問題:當訓練數據不足時,使用預訓練模型可以提高模型的泛化能力。
  • 遷移學習:將一個模型在一個任務上學到的知識,遷移到另一個相關的任務上。
  • 特征可視化:通過分析提取的特徵,可以更好地理解模型的工作原理。

從預訓練模型中提取特徵是一種非常有效的技術,可以幫助我們在各種機器學習任務中取得更好的效果。
關鍵在於選擇適合的預訓練模型,並根據具體的任務進行適當的調整。

發佈日期:

二元分類器 (binary classification) 介紹

甚麼是二元分類器

二元分類 (binary classification) 是一種機器學習中常見的任務,其目的是從兩個不同類別中將每個數據樣本歸類為其中之一。這種分類方式只有兩個類別,因此其結果是二元的。例如,對於圖像分類問題,二元分類可能用於識別猫和狗的圖像,或者用於識別垃圾郵件和非垃圾郵件的電子郵件。

在二元分類中,我們通常使用一些算法來建立一個模型,如 logistic regression, decision tree, SVM, Random forest, neural network等 來預測每個輸入數據樣本屬於哪個類別。 當我們對新數據進行預測時,該模型將輸出預測類別 (0 或 1)。

在訓練階段,通常需要提供已經標註好類別的數據來訓練模型。並在測試階段使用該模型來預測新的數據的類別,並使用常見的度量指標來評估模型的效果如精確度, AUC-ROC, F1 score等

如果您需要分類多於兩個類別的數據,則需要使用多元分類 (multiclass classification)。

和多元分類器的不同

在 TensorFlow 中,實現二元分類和多元分類器主要有兩個不同之處:

  • 損失函數: 二元分類器通常使用二元交叉熵 (binary cross-entropy) 作為損失函數。而多元分類器則常使用交叉熵 (cross-entropy) 作為損失函數。
  • 輸出層的激活函數: 二元分類器的輸出層通常使用 sigmoid 激活函數。而多元分類器的輸出層則通常使用 softmax 激活函數。

除了上述兩點的不同之外,實現二元分類器和多元分類器在 TensorFlow 中沒有太大差別。
如果使用Keras, 可以直接使用其封裝好的model,
例如:
keras.models.Sequential() 中的binary_crossentropy適用於二元分類問題

model.compile(loss='binary_crossentropy',optimizer='adam',metrics=['accuracy']) 

而 categorical_crossentropy則適用於多元分類問題.

model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['accuracy']) 

但是要注意在訓練和測試階段,多元分類需要對每個類別進行單熱編碼 ( one-hot encoding)。在 TensorFlow 中,可以使用 tf.keras.utils.to_categorical() 函數將標籤轉換為 one-hot 編碼。

優缺點比較

使用二元分類器和使用多元分類器並將其限制為兩個類別的方式之間有以下優缺點:

優點:

  • 使用二元分類器可以較為簡單地對兩個類別進行分類,而無需考慮額外的類別。
  • 如果模型使用二元交叉熵作為損失函數,則可以較容易地解釋分類結果,因為輸出層輸出的值是概率值,可以用來表示一個類別的可能性。

缺點:

  • 如果類別數量超過兩個,則無法使用二元分類器。
  • 將多元分類器限制為兩個類別可能會使模型的複雜度增加,因為必須考慮額外的類別,即使這些類別不需要分類。
  • 如果將多元分類器限制為兩個類別,則無法充分利用模型的能力,可能無法在更大范圍內解決問題。
  • 在某些情況下,使用二元分類器可能不能提供足夠的信息來解釋分類結果,因為只提供了兩個類別之間的信息。

總之, 如果您有兩個類別並且需要將數據標記為其中之一,則使用二元分類器可能是最佳選擇。如果類別數量超過兩個或者需要更多的信息來解釋分類結果,則使用多元分類器可能是更佳選擇。

發佈日期:

Tensorflow裡ResNet(殘差網路)的介紹

殘差網路ResNet

殘差網路(Residual Network,簡稱 ResNet)是一種深度卷積神經網路,它被設計用來解決深度神經網路中的梯度消失問題。

在深度神經網路中,隨著層數的增加,梯度有可能會越來越小,導致模型無法有效地學習。殘差網路通過在每一層中引入一個「殘差块」來解決這個問題。殘差块包含兩個卷積層和一個殘差路徑,殘差路徑將輸入數據直接加到輸出數據上。這樣,當殘差块的輸出數據與輸入數據相加時,梯度就不會被消失。

這邊是別人的文章介紹: https://ithelp.ithome.com.tw/articles/10264843?sc=hot

與Conv2D關鍵的不同

Conv2D就是一個提取圖片裡的特徵的方式,他是可以讓圖片也可以丟進Dense去找到共通特徵的一個關鍵,但是,Conv2D一定會需要與其他像是池化層、全連接層、輸出層等一起使用。
而殘差網路就是某個對ML非常熟的神人,所使用像是卷積層、池化層、連接層等,可有效降低梯度消失的問題的一個【已經建立好的模型】
例如: 以下為一個原始的TF模型的建立方式

model = tf.keras.Sequential([
    tf.keras.layers.Rescaling(1./255),
    tf.keras.layers.Conv2D(32, 3, activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(32, 3, activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(32, 3, activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(num_classes)
])

ResNet使用範例

而使用ResNet非常的簡單,就使用別人已建立好的ResNet就可以了,以下範例中的 ResNet 使用了 20 個 ResidualBlock,每個 ResidualBlock 中使用了 64 個濾波器,卷積核大小為 3×3,步長為 2。

import tensorflow as tf
from tensorflow.keras import layers

class ResidualBlock(layers.Layer):
    def __init__(self, filters, kernel_size, strides, use_projection=False):
        super(ResidualBlock, self).__init__()
        self.use_projection = use_projection
        self.conv1 = layers.Conv2D(filters, kernel_size, strides=strides, padding='same')
        self.bn1 = layers.BatchNormalization()
        self.relu = layers.ReLU()
        self.conv2 = layers.Conv2D(filters, kernel_size, strides=1, padding='same')
        self.bn2 = layers.BatchNormalization()
        if use_projection:
            self.projection = layers.Conv2D(filters, 1, strides=strides, padding='same')

    def call(self, inputs, training=False):
        x = self.conv1(inputs)
        x = self.bn1(x, training=training)
        x = self.relu(x)
        x = self.conv2(x)
        x = self.bn2(x, training=training)
        if self.use_projection:
            shortcut = self.projection(inputs)
        else:
            shortcut = inputs
        x += shortcut
        x = self.relu(x)
        return x

class ResNet(layers.Layer):
    def __init__(self, blocks, filters, kernel_size, strides):
        super(ResNet, self).__init__()
        self.conv = layers.Conv2D(filters, kernel_size, strides=strides, padding='same')
        self.bn = layers.BatchNormalization()
        self.relu = layers.ReLU()
        self.blocks = blocks
        self.res_blocks = [ResidualBlock(filters, kernel_size, strides) for _ in range(blocks)]

    def call(self, inputs, training=False):
        x = self.conv(inputs)
        x = self.bn(x, training=training)
        x = self.relu(x)
        for res_block in self.res_blocks:
            x = res_block(x, training=training)
        return x

inputs = tf.keras.Input(shape=(224, 224, 3))
resnet = ResNet(20, 64, 3, 2)(inputs)
outputs = layers.Dense(10, activation='softmax')(resnet)
model = tf.keras.Model(inputs, outputs)

官方介紹文件

V1版本: https://www.tensorflow.org/api_docs/python/tf/keras/applications/resnet
V2版本: https://www.tensorflow.org/api_docs/python/tf/keras/applications/resnet_v2

好多種ResNet,有甚麼差?

ResNet50, ResNet101, ResNet152 是 TensorFlow 中原始版本的 ResNet 模型,而 ResNet50V2, ResNet101V2, ResNet152V2 是 V2 版本的 ResNet 模型。以下是這些模型之間的主要區別:

  • 深度: ResNet50 的深度為 50 層,ResNet101 的深度為 101 層,ResNet152 的深度為 152 層,V2 版本的深度分別為 50 層,101 層和 152 層。
  • 架構: V2 版本的 ResNet 模型在原始版本的基礎上增加了許多改進,包括使用非常深的層 (bottleneck layer) 來減少參數數量,並在輸入層和輸出層之間使用高密度連接 (dense connection)。
  • 參數數量: V2版本的 ResNet 模型通常具有較少的參數數量,因為它們使用了更高效的架構。
  • 效能: V2版本的 ResNet 模型通常具有更好的效能,因為它們使用了更高效的架構和更少的參數。

總之, 如果要在效能和參數數量之間取得平衡, 使用 V2 版本的 ResNet 模型是個好選擇。
如果效能是優先考量,則可以使用原始版本的 ResNet 模型。

設定ResNet模型超參數

在建立殘差網路 ResNet 的模型時,有一些重要的超參數可以考慮調整,例如:

  • 卷積層數量 (num_blocks):通常來說,越多的卷積層能夠讓模型的表現更好,但也會使模型變得越大且訓練時間越長。因此可以根據實際的情況決定卷積層的數量。
  • 初始濾波器數量 (initial_filters):通常來說,使用較大的濾波器能夠讓模型的表現更好,但也會使模型變得越大且訓練時間越長。因此可以根據實際的情況決定初始濾波器的數量。
  • 激活函數 (activation):激活函數可以對輸入的數據施加非線性轉換,以便讓模型能夠學習更複雜的模式。常見的激活函數包括 ReLU、Sigmoid 和 tanh 等。
  • 優化器 (optimizer):優化器是用來更新模型參數的算法,通常會使用常見的優化器如 SGD、Adam 和 RMSprop 等。
  • 學習率 (learning rate):學習率決定了優化器更新參數的速度。如果學習率過大,則優化器可能會震蕩,無法有效地學習;如果學習率過小,則優化器可能會過慢,學習效率較低。因此可以根據實際的情況選擇合適的學習率。
  • 批次大小 (batch size):批次大小決定了每次更新參數時使用的數據數量。如果批次大小過大,則更新參數的速度會較快,但也有可能導致模型的表現變差;如果批次大小過小,則更新參數的速度會較慢,但也有可能會使模型的表現更好。因此可以根據實際的情況選擇合適的批次大小。
  • 訓練輪數 (epochs):訓練輪數決定了模型在訓練集上訓練的次數。如果訓練輪數過多,則模型有可能會對訓練集過擬合,導致在驗證集上的表現變差;如果訓練輪數過少,則模型可能無法充分學習到訓練集中的模式,導致整體的表現較差。因此可以根據實際的情況選擇合適的訓練輪數。
  • 正規化 (regularization):正規化是指在訓練過程中加入額外的限制,以防止模型過度擬合。常見的正規化方法包括 L1 正規化和 L2 正規化。
  • 丟棄率 (dropout rate):丟棄率是指在訓練過程中隨機丟棄一定比例的神經元,以防止模型過度擬合。
  • 濾波器數量 (filters):濾波器數量決定了每個卷積層使用的濾波器數量。通常來說,使用較多的濾波器能夠讓模型的表現更好,但也會使模型變得越大且訓練時間越長。因此可以根據實際的情況決定濾波器的數量。
  • 卷積層的濾波器大小 (filter size):卷積層的濾波器大小決定了每個卷積層使用的濾波器的大小。通常來說,使用較大的濾波器能夠讓模型的表現更好,但也會使模型變得越大且訓練時間越長。因此可以根據實際的情況決定濾波器的大小。

使用TunableResNet

GitHub位置: https://github.com/keras-team/keras-tuner
官方網站: https://keras.io/keras_tuner/

發佈日期:

PyCharm – 好用的python開發環境

官方網站

https://www.jetbrains.com/pycharm/

為什麼選擇PYCHARM

  • 所有 PYTHON 工具集中在一處
  • 提高生產力: 在 PyCharm 處理例程時節省時間。專注於更大的事情並採用以鍵盤為中心的方法來充分利用 PyCharm 的許多生產力功能。
  • 獲得智能幫助: PyCharm 了解您的代碼的一切。依靠它實現智能代碼完成、實時錯誤檢查和快速修復、輕鬆的項目導航等等。
  • 提升代碼質量: 編寫整潔且可維護的代碼,同時 IDE 通過 PEP8 檢查、測試協助、智能重構和大量檢查幫助您控制質量。
  • 只需您所需要的: PyCharm 由程序員設計,為程序員而設計,旨在提供高效 Python 開發所需的所有工具。

免費的社區版本和付費的專業版本

功能比較圖

專業版的優惠方案

若為在學學生,可以獲得免費帳號
https://www.jetbrains.com/community/education/#students
若以畢業,但是電子信箱仍然可以用,則也可以用學校的信箱申請學生版本使用。

另外,對於一些電腦學院或者是初期創業者也都有提供優惠,個人使用者也有優惠(更多資訊: https://www.jetbrains.com/pycharm/buy/#discounts)

下載連結

請點此下載: https://www.jetbrains.com/pycharm/download/#section=windows

點進去右邊為免費版本,左邊為付費版本,但是可以免費使用30天

發佈日期:

TensorFlow 開發者認證計劃介紹

TensorFlow認證計劃課程

以下為介紹網頁
https://www.tensorflow.org/certificate
在這個網頁當中,他們推薦了幾個課程

而我選擇了Udacity的課程(因為免費),而且可以有中文字幕

必備知識

為了順利完成考試,應試者應該了解以下知識:

  • 機器學習和深度學習的基本原則
  • 在TensorFlow 2.x 中構建機器學習模型
  • 使用深度神經網絡和卷積神經網絡構建圖像識別算法、對象檢測算法、文本識別算法
  • 使用不同形狀和大小的真實圖像可視化圖像的捲積過程,了解計算機如何“觀察”信息、繪製損失和準確率圖
  • 探索防止過擬合的策略,包括增強和丟棄策略
  • 在TensorFlow 中使用神經網絡解決自然語言處理問題

認證考試使用的工具

PyCharm
因此應熟悉在PyCharm中撰寫Python程式、Debug及Compiler。
此為社區版連結: https://www.jetbrains.com/pycharm/download/#section=windows
若是仍有學生的email信箱,則可以免費申請專業版: https://www.jetbrains.com/community/education/#students

認證考試的內容

雖然我們不一定要去獲得認證,但是從認證考試範圍可以了解,要學習Tensorflow有那些東西是官方認為必備的知識,以下為官方的認證說明文件:
TF_Certificate_Candidate_Handbook

TensorFlow開發技能

  • 在PyCharm中寫程式Python的知識,解決Python問題,並編譯和執行Python程式。
  • 了解如何查找有關 TensorFlow API 的信息,包括如何查找指南和 API(tensorflow.org 上的參考資料)。
  • 知道如何從TensorFlow API中除錯、調查和解決錯誤訊息。
  • 知道如何在tensorflow.org 之外搜尋必要知識來解決在tensorflow遇到的問題
  • 知道如何使用TensorFlow建立ML模型,其中模型大小對正在解決的問題來說是合理的。
  • 知道如何儲存ML模型並檢查模型
  • 了解不同版本的Tensorflow的相容性差異

使用TensorFlow 2.x構建和訓練神經網路模型

  • 使用TensorFlow 2.x。
  • 使用TensorFlow構建、編譯和訓練機器學習(ML)模型。
  • 預處理資料,使其準備好在模型中使用。
  • 使用模型來預測結果。
  • 為二元分類 (binary classification) 構建和訓練模型
  • 為多元分類器建構和訓練模型
  • 繪製經過訓練的模型的損失和準確性。
  • 了解如何防止過度擬合,包括資料增強(augmentation)和dropout
  • 使用預先訓練的模型(轉移學習)。
  • 從預先訓練的模型中提取特徵。
  • 確保模型的輸入處於正確的形狀。
  • 確保您可以將測試資料與神經網路的輸入形狀匹配。
  • 確保您可以將神經網絡的輸出數據與測試數據的指定輸入形狀相匹配。
  • 瞭解資料的批次載入
  • 使用回撥來觸發訓練週期的結束
  • 使用不同的來源的資料集
  • 使用不同格式的資料集,包括CSV和JSON
  • 使用tf.data.datasets裡的資料集

影像分類

瞭解如何使用TensorFlow 2.x使用深度神經網路和卷積神經網路構建影象識別和物件檢測模型。 您需要知道如何:

  • 使用 Conv2D 和池化層定義卷積神經網絡。
  • 構建和訓練模型來處理真實世界的圖像數據集。
  • 了解如何使用卷積來改進您的神經網絡。
  • 使用不同形狀和大小的真實世界圖像。
  • 使用圖像增強來防止過度擬合。
  • 使用 ImageDataGenerator。
  • 了解 ImageDataGenerator 如何根據目錄結構標記圖像。

自然語言處理(NLP)

你需要了解如何使用神經網絡張量流來解決自然語言處理問題。

您需要知道如何:

  • 使用 TensorFlow 構建自然語言處理系統。
  • 準備要在 TensorFlow 模型中使用的文本。
  • 構建使用二元分類識別一段文本類別的模型
  • 構建使用多類分類識別一段文本類別的模型
  • 在您的 TensorFlow 模型中使用詞嵌入。
  • 在您的模型中使用 LSTM 對文本進行分類以進行二分類或多分類。
  • 將 RNN 和 GRU 層添加到您的模型中。
  • 在處理文本的模型中使用 RNNS、LSTM、GRU 和 CNN。
  • 在現有文本上訓練 LSTM 以生成文本(例如歌曲和詩歌)

時間序列、序列和預測

您需要瞭解如何在TensorFlow中解決時間序列和預測問題。 您需要知道如何:

  • 訓練、調整和使用時間序列、序列和預測模型。
  • 訓練模型來預測單變數和多變數時間序列的值。
  • 為時間序列學習準備資料。
  • 瞭解平均絕對誤差(MAE)以及如何將其用於評估序列模型的準確性。
  • 使用RNN和CNN進行時間序列、序列和預測模型。
  • 確定何時使用尾隨視窗與居中視窗。
  • 使用TensorFlow進行預測。
  • 準備功能和標籤。
  • 識別和補償序列偏差。
  • 動態調整時間序列、序列和預測模型的學習率。
發佈日期:

在K8S內node js紀錄log的解決方案

千萬不要使用PM2

PM2是一個在linux裡面管理nodejs程序的好工具,它可以讓nodejs在死掉時自動控制重啟,並可於重啟次數超過時停止重啟
但是由於在K8S之中,這種管理的機制已經交由K8S去管理了,因此,若再於裡面包一層PM2,很容易出問題

可能發生的問題

  • pm2 一開始起來時會依你的參數去試著把 resource 給最大化,所以會一下子把 resource 吃滿,這會讓 k8s 覺得 是不是這個 pod 又很忙了,就馬上又起一個 pod 要來試著接手
  • pm2 會自己重啟 node process : 這會讓 k8s 不知道其實 pod 已經死了,就不會再建新的 pod 來接手

PM2其他功能的替代方案

因為PM2的部分功能與K8S重疊,不推薦使用,那關於PM2另外的文字檔log功能,則有幾種方案可解決

  • container 是吐到 stdout,k8s 的 cri 會寫到 host 上
  • 自己實作log系統

而我們公司由於管K8S的系統的運營部門不處理我們的log的儲存以及打至ELK裡的問題,所以就只能採用第二種方案,以下為我們nodeJS的解決方案log4js

使用nodeJS所推出的log管理系統

https://www.npmjs.com/package/log4js
官方的說明非常簡單好懂,下面為一個基礎使用範例,可每日分檔案,儲存三天

const log4js = require("log4js");
log4js.configure({
    appenders: {
        log: { type: "dateFile", filename: "logs/log.log", pattern: "yyyy-MM-dd", layout: { type: "pattern", pattern: "[%d] %m", }, keepFileExt: true, fileNameSep: "-", numBackups: 3 },
        error: { type: "dateFile", filename: "logs/error.log", pattern: "yyyy-MM-dd", layout: { type: "pattern", pattern: "[%d] %m", }, keepFileExt: true, fileNameSep: "-", numBackups: 3 },
    },
    categories: { default: { appenders: ["log"], level: "debug" }, error: { appenders: ["error"], level: "error" } }
});
var logger = log4js.getLogger();
var logger_error = log4js.getLogger("error");
logger.level = "debug";

exports.log = (...msg) => {
    logger.debug(...msg);
}

exports.error = (...msg) => {
    logger_error.error(...msg);
}
發佈日期:

交叉熵相關損失函數的比較

交叉熵(cross-entropy)是什麼

交叉熵是一種常用的測量兩個概率分布差異的度量。它可以用來衡量預測模型的輸出結果與真實標籤之間的差異,从而作為訓練模型的損失函數。

交叉熵的计算公式如下:

H(y, y_pred) = – ∑ y log(y_pred)

其中 y 和 y_pred 分别表示真實標籤的概率分布和預測模型的輸出概率分布。

交叉熵有一些特性,使它特别适用于衡量分類問題中模型的預測結果與真實標籤之間的差異:

交叉熵越小,預測模型的輸出結果就越接近真實標籤,模型的預測能力就越強。
当預測模型的輸出結果完全符合真實標籤時,交叉熵等于零。
交叉熵是一個非負數,且在模型預測結果與真實標籤完全不同時,交叉熵最大。

交叉熵相關損失函數

有以下兩種

  • categorical_crossentropy
  • sparse_categorical_crossentropy

兩者都是用於計算分類問題中模型預測結果與真實標籤之間的交叉熵的損失函數。但是它們有一些重要的區別。

1、在 “categorical_crossentropy” 中,標籤必須是一個 one-hot 編碼,即對每個類別都指定一個二元(0/1)標籤。
2、在 “sparse_categorical_crossentropy” 中,標籤可以是一個整數,表示每個類別的索引。在計算交叉熵損失時,會對這些整數標籤進行單熱編碼。

如果你的標籤已經是 one-hot 編碼,則應使用 “categorical_crossentropy”。如果你的標籤是整數,則應使用 “sparse_categorical_crossentropy”。

通常情況下,使用 “sparse_categorical_crossentropy” 可能比較方便,因為標籤可以直接表示為整數,而不需要先對它們進行 one-hot 編碼。但是,使用 “categorical_crossentropy” 也是可以的,只需要將標籤進行 one-hot 編碼即可。

單熱編碼(one-hot encoding)

單熱編碼(one-hot encoding)是一種將類別特徵轉化為向量的方法。

假設有一個有 N 個不同類別的特徵,那麼我们就可以將每個類別都表示為一個 N 维的二元向量,其中只有一個元素為 1,其余元素都為 0。例如,如果類別有 A、B、C 三個可能的取值,那麼我們就可以將它們分别表示為:

A: [1, 0, 0]
B: [0, 1, 0]
C: [0, 0, 1]

通常情况下,單熱編碼通常用於處理分類問題,並且可以用於訓練深度學習模型。它的主要作用是將類別特徵轉化為可以被訓練模型理解的數值型特徵,以便訓練模型。

發佈日期:

使用數據增強加強圖像辨識準確率

數據增強

數據增強(Data Augmentation)是一種在不增加真實數據的情況下,通過對現有數據進行變化來增加數據集大小的方法。
請參見: https://www.tensorflow.org/api_docs/python/tf/keras/preprocessing/image/ImageDataGenerator
常見的數據增強技術包括:

  • 尺度變換: 對圖像進行放大或縮小。
  • 旋轉: 對圖像進行旋轉。
  • 平移: 對圖像進行平移。
  • 剪裁: 對圖像進行剪裁。
  • 翻轉: 對圖像進行水平或垂直翻轉。
  • 調整亮度: 對圖像的亮度進行調整。
  • 調整對比度: 對圖像的對比度進行調整。

通過使用這些技術,可以從現有的數據集中生成新的數據,以增加數據集的大小

使用數據增強的範例 – 使用ImageDataGenerator

以下為一個簡單範例

# 建立模型
model = Sequential()
# 加入多個卷積層和池化層
model.add(Conv2D(filters=32, kernel_size=(3,3), activation='relu', input_shape=(img_height,img_width,3)))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(filters=64, kernel_size=(3,3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(filters=128, kernel_size=(3,3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))

# 將特徵圖拉平
model.add(Flatten())

# 加入多個全連接層
model.add(Dense(units=256, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(units=128, activation='relu'))
model.add(Dropout(0.5))

# 加入輸出層
model.add(Dense(units=52, activation='softmax'))

# 編譯模型
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

# 使用數據增強
datagen = ImageDataGenerator(
rotation_range=30,
width_shift_range=0.2,
height_shift_range=0.2,
horizontal_flip=True
)

# 訓練模型
model.fit_generator(
datagen.flow(x_train, y_train, batch_size=32),
steps_per_epoch=len(x_train) / 32,
epochs=10,
validation_data=(x_val, y_val)
)

數據增強範例2 – 載入圖片decode_jpeg後隨機改變圖像

#现在我们的jpg文件进行解码,变成三维矩阵
def load_preprosess_image(path,label):
    #读取路径
    image=tf.io.read_file(path)
    #解码
    image=tf.image.decode_jpeg(image,channels=3)#彩色图像为3个channel
    #将图像改变为同样的大小,利用裁剪或者扭曲,这里应用了扭曲
    image=tf.image.resize(image,[360,360])
    #随机裁剪图像
    image=tf.image.random_crop(image,[256,256,3])
    #随机上下翻转图像
    image=tf.image.random_flip_left_right(image)
    #随机上下翻转
    image=tf.image.random_flip_up_down(image)
    #随机改变图像的亮度
    image=tf.image.random_brightness(image,0.5)
    #随机改变对比度
    image=tf.image.random_contrast(image,0,1)
    #改变数据类型
    image=tf.cast(image,tf.float32)
    #将图像进行归一化
    image=image/255
    #现在还需要对label进行处理,我们现在是列表[1,2,3],
    #需要变成[[1].[2].[3]]
    label=tf.reshape(label,[1])
    return image,label

梗圖分享

發佈日期:

模型的權重與偏差值

偏差值的功能

偏差值 在神經網絡中扮演著一個非常重要的角色,它就像是一個額外的參數,讓模型能夠更靈活地擬合數據。

  • 調整激活函數的輸出範圍:
    • 想像一下,激活函數就像是一個門檻,只有當輸入超過這個門檻時,神經元才會被激活。偏差值就像調整這個門檻的高度,讓神經元更容易或更難被激活。
    • 舉例來說,如果我們希望神經元在輸入較小的值時就更容易被激活,就可以增加偏差值。
  • 增加模型的表達能力:
    • 偏差值的存在,讓模型可以學習到更複雜的模式。
    • 它就像是在模型中加入了一個常數項,使得模型的輸出不總是過原點,而是可以根據數據的分布進行調整。
  • 影響模型的學習過程:
    • 偏差值的初始化值會影響模型的收斂速度和最終的性能。
    • 合理的偏差值初始化可以幫助模型更快地找到最優解。

偏差值與權重的關係

  • 權重 決定了輸入特徵對神經元輸出的影響程度。
  • 偏差 則是對輸出的一個常數偏移。
  • 共同作用:權重和偏差共同決定了神經元的輸出。權重負責提取特徵,而偏差則負責調整輸出範圍。

神經元的權重與偏差

在神經網絡中,權重 (weight) 和偏差 (bias) 是模型的兩個重要參數。

權重 (weight) 指的是神經網絡中的輸入層和輸出層之間的連接強度。每個神經元都有一個權重矩陣,表示與該神經元相連的輸入張量的強度。輸入張量與輸出張量之間的權重越大,該神經元對輸出的貢獻就越大。

偏差 (bias) 指的是神經網絡中的偏移量。每個神經元都有一個偏差值,表示該神經元的輸出在不考慮輸入的情況下的預設值。偏差值可以控制神經網絡的輸出範圍,並且可以用於控制模型的準確性。

在訓練神經網絡模型時,通常會使用梯度下降法來調整權重和偏差的值,以使得模型的輸出與真實值的差異最小。

設定神經元的偏差值

在訓練神經網絡模型時,通常可以自己設定神經元的偏差值。

例如,在 TensorFlow 中可以使用以下方式創建一個帶有偏差的神經元:

import tensorflow as tf

# 創建一個帶有偏差的神經元
neuron = tf.keras.layers.Dense(units=1, bias_initializer=tf.constant_initializer(1.0))

上面使用了 bias_initializer 參數指定了偏差的初始值為 1.0。

使用梯度下降法調整偏差值

在訓練神經網絡模型時,通常會使用梯度下降法來調整偏差的值,以使得模型的輸出與真實值的差異最小。通常會使用 TensorFlow 的自動微分機制來計算模型的梯度,並使用梯度下降法調整偏差的值。

簡單範例

import tensorflow as tf

# 創建一個帶有偏差的神經元
neuron = tf.keras.layers.Dense(units=1, bias_initializer=tf.constant_initializer(1.0))

# 創建模型
model = tf.keras.Sequential([neuron])

# 定義損失函數和優化器
loss_fn = tf.keras.losses.MeanSquaredError()
optimizer = tf.keras.optimizers.SGD(learning_rate=0.1)

# 訓練模型
for epoch in range(10):
  # 訓練數據
  x_train = [1.0, 2.0, 3.0, 4.0]
  y_train = [0.0, 0.0, 0.0, 0.0]

  # 將訓練數據放入模型
  for x, y in zip(x_train, y_train):
    with tf.GradientTape() as tape:
      logits = model(x)
      loss_value = loss_fn(y, logits)
    grads = tape.gradient(loss_value, model.trainable_variables)
    optimizer.apply_gradients(zip(grads, model.trainable_variables))

# 檢查神經元的偏差值
print(neuron.bias)  # 輸出: [0.9]

最後我們檢查了神經元的偏差值,可以看到它已經從 1.0 調整到了 0.9。

手動設定神經元的偏差值

以下為一個簡單範例

import tensorflow as tf

# 創建一個帶有偏差的神經元
neuron = tf.keras.layers.Dense(units=1, bias_initializer=tf.constant_initializer(1.0))

# 創建模型
model = tf.keras.Sequential([neuron])

# 定義損失函數和優化器
loss_fn = tf.keras.losses.MeanSquaredError()
optimizer = tf.keras.optimizers.SGD(learning_rate=0.1)

# 訓練模型
for epoch in range(10):
  # 訓練數據
  x_train = [1.0, 2.0, 3.0, 4.0]
  y_train = [0.0, 0.0, 0.0, 0.0]

  # 將訓練數據放入模型
  for x, y in zip(x_train, y_train):
    with tf.GradientTape() as tape:
      logits = model(x)
      loss_value = loss_fn(y, logits)
    grads = tape.gradient(loss_value, model.trainable_variables)
    optimizer.apply_gradients(zip(grads, model.trainable_variables))

# 檢查神經元的偏差值
print(neuron.bias)  # 輸出: [0.9]

# 手動設定神經元的偏差值
neuron.bias.assign([1.0])

# 再次檢查神經元的偏差值
print(neuron.bias)  # 輸出: [1.0]

發佈日期:

tensorflew的自動求導機制

什麼是自動求導機制

在 TensorFlow 中,有一種特殊的張量類型叫做梯度張量,可以用於計算模型的梯度。

TensorFlow 的梯度張量是一種特殊的張量,其中包含了模型中每個變量的梯度信息。梯度張量是 TensorFlow 的自動微分機制的基礎,可以通過 TensorFlow 的自動微分機制來計算模型的梯度。

使用方法介紹

使用 GradientTape 類的方法是:

在計算圖的上下文中創建一個 GradientTape 對象。
使用 GradientTape 對象的 watch 方法監視計算圖中的變量。
執行計算圖,並在計算圖中使用 TensorFlow 的運算符操作張量。
使用 GradientTape 對象的 gradient 方法計算模型的梯度。

使用範例

在機器學習中,我們經常需要計算函數的導數。TensorFlow 提供了強大的自動求導機制來計算導數。以下程式展示了如何使用 tf. GradientTape()方法計算函數,y(x)=x^2在x=3時的導數:

 import tensorflow as tf
x = tf. Variable (initial value=3.)
with tf.GradientTape () as tape:
    #所有計算步驟都會被記錄以用於求導
    y=tf.sguare (x)
y_grad = tape.gradient (y, x)#計算y關於x的導數
print (ly, y_grad]) 

輸出如下:

[array ([9.1, dtype=float32), array ([6.], dtype=float32)]