Wednesday, December 16, 2020

Install Charm Crypto in Mac OS Catalina 10.15.7

Charm Crypto
Developed by Akinyele, Joseph A, Charm Crypto is a simplified Python wrapper of PBC Library. There are many researchers using this library to build prototypes for their cryptographic protocols. In fact, its performance is comparable to the original C version of PBC (I also did some experiments and found that it is actually faster than JPBC, the Java wrapper of PBC). 

Dependencies Installation
To use Charm Crypto in Mac OS Catalina, you need to have the following items preinstalled:

1. Homebrew
It is for running the subsequent commands below.
To install the latest version of homebrew, check the script in the official brew website.

2. GMP Library
Install command: brew install gmp

3. PBC Library
Install command: brew install pbc

4. OpenSSL
Install command: brew install openssl@1.1

5. WGET
Install command: brew install wget

Charm Crypto Installation
After installing the dependencies above, run the following steps:

1. Download the latest source code
Command: git clone https://github.com/JHUISI/charm.git ; cd charm

2. Run the configure in root privileges and with the brew-installed version of openssl
Command: sudo ./configure.sh --extra-cflags="-I/usr/local/opt/openssl/include" --extra-ldflags="-L/usr/local/opt/openssl/lib

(Extra CFLAGS and LDFLAGS are required because brew will not install the openssl into /usr/lib)

3. Run the compilation and installation
Command: sudo make install

4. Run the post-installation testing
Command: sudo make test

After installation, you should be able to import schemes.* and charm.* freely in Python3 freely.

Screenshot
Once you see most of the items are passed, you can start programming with Charm Crypto.
Some example schemes can be found in charm/schemes directory.

Monday, December 7, 2020

實作:利用 PyTorch LSTM 估計未來氣温

簡介
Long Short Term Memory (LSTM) 是一種對時序有記憶的神經網絡。簡單來講,你可以幻想它是一種有短暫及長期記憶的細胞。只要你不斷按順序地訓練它,日子有功,它就會記住事物的先後次序(例如:你每次都用 A-B-C 的順序去訓練它,以後它只要見到 A,就會想起下一個是 B)。

這種神經網絡,對自然語言處理 (Natural Language Processing) 特別有用:因為它能記住句子的先後順序,繼而找出代名詞原本的意思。 例如「小明去了踩單車,他覺得很開心」這一句中,使用 LSTM,系統就能運用短暫記憶,找出「他」所指的主語,是句子開頭的「小明」。

除了 NLP 之外,LSTM 還特別適合用來預測有規律的時序資料 (time-series data)。例如假設每年天氣都是有四季,而且每年氣温都差不多的話,LSTM 就能找出這個潛在的規律,從而推算出將來某月的氣温大約會是多少。還有,通訊系統的訊號、看似沒有規律的雜訊等等,也非常適合用 LSTM 來找出它的潛在規律。

是次實驗,我會使用新加坡的氣温歷史數據,訓練 LSTM,試試到底它能否有效預測將來的温度。不過,由於新加坡沒有四季,而且氣温有可能隨雨量及雲量影響,所以準繩度理應不會太高。但怎樣也好,姑且一試無妨。  

---

幾個重要的變數
是次實驗,我用了這些變數:

  • 原資料的長度為 466 個數據。
  • 我把資料切割成 448 份 [x1 x2 x3 ... x16 x17 x18],然後把期望目標設為 [x19]
    換句話說,我把頭 18 個月的數據進 LSTM,然後期望它會估計到第 19 個月的氣温,
    而這件事會重覆 448 次。
  •  我把 70% 的資料用作訓練,30% 用作驗證。
  • 我使用了 SciKit 的 MinMaxScaler,將所有輸入輸出數據,都以 fit_transform 正規化,
    之後,估算完成後,我再用 inverse_transform 還原。

關於 LSTM 的變數,我設定成:

  • 資料維度 (input_size / features / input_dimension) 為 1,因為氣温是一維的資料。
  • 次序長度 (sequence_len) 為 18,因為我順序放 18 個月的氣温資料。
  • 隱藏層大小 (hidden_size) 為 500,因為我估計會有 500 個特徵值得留意。
  • 層數 (num_layers) 為 3,所以會同時有三個短暫記憶的空間。
  • 我設定了 batch_first=True,所以資料結構是 (batch, sequence, features),
    也就正乎合 for loop DataLoader 時返回來的資料結構,省回轉來轉去的代碼。
    (RNN 全部都有這種選項,因為它的訓練模式與其他相異,
    x1 和 x2 是放進同一個 cell,而非像 linear regression 那種,是放進兩個不同 cells。)

關於訓練的變數:

  • 訓練包大小 (batch size) 為 20, 因為本人的電腦記憶體較少 ,不適宜大包大包訓練。 
  • 我運行了 500 個 epoch,因為我發現次數再多, loss 也沒再變少。
  • 我使用了 Mean Square Error (MSE) 來做 loss function,兩個氣温相差再平方,很直覺。

---

演示代碼

https://github.com/cmcvista/MLHelloWorld/blob/main/LSTMPyTorch/LSTMTemperaturePrediction.ipynb

---

預測結果

紅色為預測結果,藍色為實際結果。

由此可見,單純使用 LSTM 並不太準確。
我估計原因是因為,一來新加坡的氣温變化不大,所以難以準確預測,
二來就是訓練次數不足(或者 optimization strategy 太保守),以至它仍未學足 pattern。

但另一方面,雖然方向估錯,但預測結果的形狀,的確有點像實際數據的形狀。
所以,這也算是一個「有意義的發現」。

---

小結
LSTM 與其他傳統的神經網絡不同,它以 RNN 的形式運作,以致可以認出時間次序。
雖然初步來看,用作預測氣温並不可靠,但用來找出數據的規律,看來也還可以。

---

參考:

[1] - https://stackabuse.com/time-series-prediction-using-lstm-with-pytorch-in-python

 

Wednesday, November 25, 2020

常見的 ML Loss Function: MSE, Hinge 及 Cross Entropy

簡介
在 ML 的領域中,Loss Function 是一種量化「機器預測值 (predicted value)」和「實際期望值 (desired value)」之間差距的一種工具。簡單來講,如果機器預測的結果與實際期望一致,這個模型就「沒有任何資料損失」,也就是說,Loss Function 的輸出會等於 0。相反,如果兩者不一致,損失就應該越大,故此數值輸出應該越高。

以上概念雖然簡單, 但實際上, 不同的 Projects 中均會採用不同的 Loss Function,以便有效反映資料損失的程度。所以,在實際應用中,往往令人覺得很困惑:到底什麼情景,才能用這個 Loss Function 呢?本文會介紹三種十分常見的 Loss Function,並輔以「正常人能理解的文字」,幫助大家更容易明白,以及作出正確選擇。

---

Mean-Squared Error (MSE) 均方差
MSE 是最通用,最易理解的 Loss Function,它的目標是找出兩點的距離。
這種算法不限定期望值的範圍,基本上任何輸出(例如 [-1, 1], [0, 1], [0, inf) 等)都可以用。

首先,我們需用最簡單的方法,計算出兩點距離,也就是 x2 - x1
不過,它會產生以下問題:

假設 x1 = -4,x2 = 3:

  • 使用 x2 - x1 的公式,我們得出距離為 3-(-4) = 7

但當 x1 = 4,x2 = -3 的情況:

  • 使用 x2 - x1 的公式,我們將得出距離為 -3-4 = -7

因為 Loss Function 的定義是「數值越細,損失越少」,這個情況下,明明兩個例子的實際距離均是 7,我們卻得到不一樣的結果。為了防止這種情況,最簡單的方法,就是把結果平方,變成以下公式:

  • 使用 (x2 - x1) ^2,兩個例子均能得到 (7)^2 = (-7)^2 = 49

這樣就能解決正負問題,而且也能做到「距離越大,損失越多」的感覺。
(例如 2^2 = 4,但 7^2 = 49,原本只差 7-2=5,卻做到了 49/4=12 倍的差別)

附上公式代碼:

def MSE(yHat, y):
    return np.sum((yHat - y)**2) / y.size 

---

Hinge Loss 鉸鏈損失
這種 Loss Function 只適用於期望值是 -1 或 +1 的情況。例如,在 SVM 二元分類器 (binary classifier) 的情況中,只要分類正確,損失值就應該是 0。相反,若果分類錯誤,Loss Function 就應該要懂得表達有多少差距。

這種特性,可以用 Loss = max(0, 1 - desired value * predicted value) 表示。

例如當 predicted value = +1,desired value = +1 (分到同類)時:

  • Loss = max(0, 1 - 1*1) = max(0, 0) = 0

當 predicted value = +0.8,desired value = +1 (分到同類,但不夠肯定)時:

  • Loss = max(0, 1-0.8) = max(0, 0.2) = 0.2

當 predicted value = -0.8,desired value = +1 (分錯類)時:

  •  Loss  = max(0, 1-(-0.8)) = max(0, 1.8) = 1.8

這樣,Loss Function 就能有效表示分錯類,或者分得不夠開的情況。

附上公式代碼:

def Hinge(yHat, y):
    return np.max(0, 1 - yHat * y)

---

Cross Entropy Loss 交叉熵損失
這種 Loss Function 特別適合期望值在 [0, 1] 連續數據範圍的情況,例如概率等等。它與 MSE 有一個相似之處:當預測值與期望值的差距越大,得到的懲罰就會指數性上升。例如當期望值 = 1, 我們可以用下列圖表及公式表示 Cross Entropy:

公式:Loss = - p(x) * log (q(x))
若 desired value = 1,則 p(x) = 1,q(x) = predicted value;
若 desired value = 0,則 p(x) = 1,q(x) = 1-predicted value。

當 desired value = 1 及 predicted value = 1 時:

  • Loss = -1*log(1) = 0

當 desired value = 0 及 predicted value = 0.99 時:

  • Loss = -1*log(1-0.99) = -1*log(0.01) = -2

由此可見,當預測值與期望值越背道而馳,損失就越高。

附上公式代碼:

def CrossEntropy(yHat, y):
    if y == 1:
      return -log(yHat)
    else:
      return -log(1 - yHat)

---

參考:

[1] - https://ml-cheatsheet.readthedocs.io/en/latest/loss_functions.html

[2] - https://blog.csdn.net/hustqb/article/details/78347713