ZamaAI が開発するTFHEのアプリケーションライブラリ、concrete-mlのチュートリアルを動かす

## 概要

準同型暗号とは、暗号の中でも、暗号化した後に計算をすることのできる暗号のことです。
今回は、その準同型暗号の中でも、格子暗号と呼ばれる暗号の研究開発をしているZamaAIというスタートアップ企業のライブラリ、

concrete-ml

https://github.com/zama-ai/concrete-ml

について、チュートリアルを動かすことで

- チュートリアルでどのようなことをやっているか（やれるのか）
- どのくらいの時間で実行できるのか

について解説したいと思います。

このライブラリを使うと、
準同型暗号のみを、秘密計算の手法として用いた機械学習の推論が実行できます。

以前書いた

https://qiita.com/kenmaro/items/2c952ff9c16278ef2a41

こちらの記事では、秘密分散や、準同型暗号と秘密分散をハイブリッドで使った推論についても書いていますので、
興味のある方はぜひご覧ください。
ハイブリッド方式が一番実用性があるということに言及しています。

## ZamaAIについて

ZamaAIは、フランスのパリに拠点を置くZamaAIというスタートアップで、
準同型暗号の研究については世界でも１、２を争っている企業です。
彼らの開発している concrete というライブラリはRustで実装された完全準同型暗号である
格子暗号のライブラリで、そのconcrete をベースにして、機械学習の推論などを暗号状態で実行することのできるアプリケーションレイヤとして concrete-mlは開発されています。

## 使っている完全準同型暗号について

ZamaAIは、TFHEとよばれるもともとはビットを暗号化する形の暗号を
拡張し、整数や任意の少数をエンコードしてLUTを参照できる形の
プログラマブルブートストラップ（ここではZama方式と呼びます）を発表し、それ以来TFHEとZama方式の手法をOSSのライブラリで研究開発しています。

このプログラマブルブートストラップ法を搭載したZama方式の格子暗号については、

https://qiita.com/kenmaro/items/d78f012c522594126afe

ここに以前記事を書いたので時間が許せばぜひ読んでみてください。

## 以前の記事との相違点

https://qiita.com/kenmaro/items/95df78f96f57b5cc5352#brevitas-%E3%81%8B%E3%82%89%E3%81%AE%E5%AD%A6%E7%BF%92%E3%81%95%E3%82%8C%E3%81%9F%E3%83%A2%E3%83%87%E3%83%AB%E3%81%A7cifar10%E3%82%92%E6%8E%A8%E8%AB%96

以前こちらに同じ様にconcrete-mlを動かしたときの記事を書きました。

この時から、concrete-mlは大きく改善した点があるので、そちらを中心に読んでいただければと思います。

### 改善された点

以前記事を書いた2023/02 あたりではバージョン０.6 とかでしたが、
2023/08 現在では 1.1 となり、

https://github.com/zama-ai/concrete-ml/releases

できることも増え、速度も大きく改善されていました。
特に、ニューラルネットの推論速度が非常に速くなっています。

MNISTデータセットに対してニューラルネット（全結合層を使用）で推論をするチュートリアルがあるのですが、チュートリアルに使われるモデルも前よりとても深くなり、動作も高速になっています。





## 試したチュートリアル


ここで、彼らの使っているのは完全準同型暗号であり、
基本的にモデルへの入力は暗号化された後に復号されることなく計算され、クライアントはほとんどすべての計算をサーバに委譲することができます。


この前提のもとで、
今回試したのは以下のチュートリアルです。


- ロジスティック回帰の推論
- 決定木の推論
- XGBoostモデルの推論
- ニューラルネットの全結合モデルの推論


### 平文での実行と暗号文での実行

平文での実行は、concrete-ml のAPIでは 

```python
fhe_predictions = concrete_model.best_estimator_.predict(x_test, fhe="simulation")
```

の様に実行でき、
この`simulation`は、使用するビット演算のロジックはそのままで、暗号文を用いずに実行するために準備されています。
`simulation`は速度ではなく、ビット演算をした時の精度の劣化について検証したいときに使うために用意されています。

```
fhe_predictions = concrete_model.best_estimator_.predict(x_test, fhe="execute")
```

`execute`とすると、ロジックはビット演算ベースで、実際に暗号文を用いて推論が実行できます。
`execute`で実行した時の精度劣化は`simulation`の時と変わりませんが、こちらは暗号状態での推論によりどのくらい速度に影響が出るかを検証するための設定になっています。

## 結果

試した環境は、私のMacBookProです。




### ロジスティック回帰の推論

#### データセット

```python
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from concrete.ml.sklearn import LogisticRegression

# Lets create a synthetic data-set
x, y = make_classification(n_samples=100, class_sep=2, n_features=30, random_state=42)
```

により手動生成したデータを使っています。


`暗号状態での実行`

```
time: 0.024985551834106445
In clear  : [0 0 0 0 1 0 1 0 1 1 0 0 1 0 0 1 1 1 0 0]
In FHE    : [0 0 0 0 1 0 1 0 1 1 0 0 1 0 0 1 1 1 0 0]
Similarity: 100%
```

20件の予測を0.025秒程度で実行できています。



### 決定木の推論

#### データセット

こちらのクレジットカードスコアのデータを元に作られています。

https://www.kaggle.com/code/ajay1735/my-credit-scoring-model

上のプログラムを元に作ったモデルに対して、
５件のテストデータを入れて推論しています。

#### モデルパラメータ

```
print(classifier.n_classes_)
print(classifier.get_depth())
print(classifier.get_n_leaves())
print(classifier.n_features_in_)
```
での結果が

```
2
24
388
10
```

となっているように、深さは24あり、リーフが388個あるので、なかなか大きなモデルになっています。’

`平文での実行`

```
0m3.174s
accuracy score :  1.0
f1 score :  1.0
precision score :  1.0
recall score :  1.0 
```

`暗号での実行`

```
5件　13m15.753s
accuracy score :  0.8
f1 score :  0.4444444444444445
precision score :  0.4
recall score :  0.5
```




### XGBoost モデルの推論

#### データセット
こちらのtitanic データセットを使用しています。

https://www.kaggle.com/c/titanic/


#### モデルパラメータ

平文によりグリッドサーチされて選ばれたモデルに対して、418件のテストデータを推論しています。

```
{'learning_rate': 0.01, 'max_depth': 3, 'n_bits': 2, 'n_estimators': 1}
```
XGBoostのモデルは木が１本で、最大の深さが３
とかなり小さいモデルになっています。


`暗号状態での実行`

```
Key generation time: 1.12s
Total execution time for 418 inferences: 74.53s
Execution time per inference in FHE: 0.18s
Prediction similarity between both Concrete ML models (quantized clear and FHE): 100.00%
Accuracy of prediction in FHE on the test set 75.84%

real    2m11.596s
```

418件の推論が75秒程度で完了しており、
実質１件0.18秒くらいで推論できていることがわかります。


### ニューラルネットの全結合モデルの推論

#### データセット
MNISTを使用しています。

#### モデルパラメータ
全結合層[28 * 28, 192, 192, 192, 10]の
隠れ層３層のモデルを推論しています。
モデルの学習は

https://qiita.com/kenmaro/items/95df78f96f57b5cc5352#brevitas-%E3%81%8B%E3%82%89%E3%81%AE%E5%AD%A6%E7%BF%92%E3%81%95%E3%82%8C%E3%81%9F%E3%83%A2%E3%83%87%E3%83%AB%E3%81%A7cifar10%E3%82%92%E6%8E%A8%E8%AB%96

こちらでも書いた様に、Xilinx が開発しているライブラリBrevitasを用いて8ビット上で学習されたモデルに対して暗号状態で推論を実行しています。


#### 精度制約
8ビットの精度で推論実行しています。

`平文での実行` 

```
4. Checking accuracy with the FHE simulation mode (length 2)
Accuracy in Simulation with length 2: 1/2 = 0.5000, in 6-bits
{'FHE simulation short': 0.5}

real    0m40.617s
```

`暗号状態での実行`

```
4. Checking accuracy in FHE (length 2)
WARNING: The generated random seed is not crypto secure
KeySetCache: miss, regenerating /tmp/keycache/3592600221116122479/0_0
WARNING: The generated random seed is not crypto secure
Accuracy in FHE with length 2: 1/2 = 0.5000, in 6-bits
{'FHE short': 0.5}

real    2m4.026s
```

約１件１分ほどの推論時間となっています。



## 最後に

今回は、現時点で
完全準同型暗号を用いた機械学習の推論をCPUで実行できる一番簡単で高速なライブラリ

concrete-ml

について、チュートリアルを実行することで現在の準同型暗号オンリーで機械学習モデルを推論する時の
精度や速度の制約について感覚値が掴めたのかなと思います。


今回はこの辺で。


@kenmaro