Moose框架

一 简介

Moose - 3MoosePC with secret sharing; secure against semi-honest adversaries; focused on data processing and machine learning.

Moose 是一个安全的分布式数据流框架,由编译器、运行时、Python eDSL 和绑定组成。它适用于但不限于加密机器学习和数据处理。它已经准备好生产并且主要用 Rust 编写。

计算使用 eDSL 或通过 Rust API 编程来表达。数据流图中的每个操作都固定到一个位置,该位置代表物理机器或几种虚拟执行单元之一。Moose 目前包括对更简单的机器学习模型的支持,以及由安全多方计算 (MPC) 以复制秘密共享的形式支持的虚拟布局。请参阅docs.rs、examples、tutorials或我们的白皮书了解更多详细信息。

API 版本文档: https://docs.rs/moose/latest/moose/

setup:
moose针对所有计算都在位环MP-SPDZ中完成的三方使用算术复制秘密共享协议进行 基准测试。128Moose 默认使用复制的秘密共享运行,而在其中 MP-SPDZ可以作为replicated-ring-party.x可执行文件找到。

所有测试都使用 4 台机器 - 一台充当协调器,即编译并将计算发送给其他机器,而其余三台机器执行协议

使用的软件版本是moosev0.2.2 和MP-SPDZv0.3.2。

二 安装

  1. 源码安装编译

https://github.com/tf-encrypted/moose/blob/main/DEVELOP.md

  1. python安装使用

pip install moose-python

cargo install moose
Debian/Ubuntu:sudo apt install libopenblas-dev
苹果系统:homebrew install openblas

  1. docker 镜像

https://hub.docker.com/r/tfencrypted/moose

三 用法

import numpy as np
import pymoose as pm

alice = pm.host_placement("alice")
bob = pm.host_placement("bob")
carole = pm.host_placement("carole")
replicated = pm.replicated_placement("rep", players=[alice, bob, carole])

@pm.computation
def simple_computation(
    x: pm.Argument(placement=alice, vtype=pm.TensorType(pm.float64)),
    y: pm.Argument(placement=bob, vtype=pm.TensorType(pm.float64)),
):
    with alice:
        x = pm.cast(x, dtype=pm.fixed(14, 23))

    with bob:
        y = pm.cast(y, dtype=pm.fixed(14, 23))

    with replicated:
        z = pm.add(x, y)

    with carole:
        v = pm.cast(z, dtype=pm.float64)

    return v

# 定义端口
runtime = pm.GrpcMooseRuntime({
    alice: "localhost:50000",
    bob: "localhost:50001",
    carole: "localhost:50002",
})
runtime.set_default()

result = my_computation(
    x=np.array([1.0, 2.0], dtype=np.float64),
    y=np.array([3.0, 4.0], dtype=np.float64),
)
print(result)

线性回归

"""Example of linear regression training with label-split data."""
import argparse
import logging
import unittest

import numpy as np
import pytest
from absl.testing import parameterized

import pymoose as pm
from pymoose.logger import get_logger

FIXED = pm.fixed(8, 27)
# Rust compiler currently supports only limited set of alternative precisions:
# FIXED = pm.fixed(14, 23)


def generate_data(seed, n_instances, n_features, coeff=3, shift=10):
    rng = np.random.default_rng()
    x_data = rng.normal(size=(n_instances, n_features))
    y_data = np.dot(x_data, np.ones(n_features) * coeff) + shift
    return x_data, y_data


def mse(y_pred, y_true):
    return pm.mean(pm.square(pm.sub(y_pred, y_true)), axis=0)


def mape(y_pred, y_true, y_true_inv):
    return pm.abs(pm.mul(pm.sub(y_pred, y_true), y_true_inv))


def ss_res(y_pred, y_true):
    squared_residuals = pm.square(pm.sub(y_true, y_pred))
    return pm.sum(squared_residuals, axis=0)


def ss_tot(y_true):
    y_mean = pm.mean(y_true)
    squared_deviations = pm.square(pm.sub(y_true, y_mean))
    return pm.sum(squared_deviations, axis=0)


def r_squared(ss_res, ss_tot):
    residuals_ratio = pm.div(ss_res, ss_tot)
    return pm.sub(pm.constant(1.0, dtype=pm.float64), residuals_ratio)


class LinearRegressionExample(parameterized.TestCase):
    def _build_linear_regression_example(self, metric_name="mse"):
        x_owner = pm.host_placement(name="x-owner")
        y_owner = pm.host_placement(name="y-owner")
        model_owner = pm.host_placement(name="model-owner")
        replicated_plc = pm.replicated_placement(
            players=[x_owner, y_owner, model_owner], name="replicated-plc"
        )

        @pm.computation
        def my_comp(
            x_uri: pm.Argument(placement=x_owner, vtype=pm.StringType()),
            y_uri: pm.Argument(placement=y_owner, vtype=pm.StringType()),
            w_uri: pm.Argument(placement=model_owner, vtype=pm.StringType()),
            metric_uri: pm.Argument(placement=model_owner, vtype=pm.StringType()),
            rsquared_uri: pm.Argument(placement=model_owner, vtype=pm.StringType()),
        ):
            with x_owner:
                X = pm.atleast_2d(
                    pm.load(x_uri, dtype=pm.float64), to_column_vector=True
                )
                # NOTE: what would be most natural to do is this:
                #     bias_shape = (slice(shape(X), begin=0, end=1), 1)
                #     bias = ones(bias_shape, dtype=float)
                # but this raises an issue about accomodating python native values in
                # the ASTTracer, something we've discussed and temporarily tabled in
                # the past. For now, we've decided to implement squeeze and unsqueeze
                # ops instead.
                # But we have a feeling this issue will continue to come up!
                bias_shape = pm.shape(X)[0:1]
                bias = pm.ones(bias_shape, dtype=pm.float64)
                reshaped_bias = pm.expand_dims(bias, 1)
                X_b = pm.concatenate([reshaped_bias, X], axis=1)
                A = pm.inverse(pm.dot(pm.transpose(X_b), X_b))
                B = pm.dot(A, pm.transpose(X_b))
                X_b = pm.cast(X_b, dtype=FIXED)
                B = pm.cast(B, dtype=FIXED)

            with y_owner:
                y_true = pm.atleast_2d(
                    pm.load(y_uri, dtype=pm.float64), to_column_vector=True
                )
                if metric_name == "mape":
                    y_true_inv = pm.cast(
                        pm.div(pm.constant(1.0, dtype=pm.float64), y_true),
                        dtype=FIXED,
                    )
                totals_ss = ss_tot(y_true)
                y_true = pm.cast(y_true, dtype=FIXED)

            with replicated_plc:
                w = pm.dot(B, y_true)
                y_pred = pm.dot(X_b, w)
                if metric_name == "mape":
                    metric_result = mape(y_pred, y_true, y_true_inv)
                else:
                    metric_result = mse(y_pred, y_true)
                residuals_ss = ss_res(y_pred, y_true)

            with model_owner:
                residuals_ss = pm.cast(residuals_ss, dtype=pm.float64)
                rsquared_result = r_squared(residuals_ss, totals_ss)

            with model_owner:
                w = pm.cast(w, dtype=pm.float64)
                metric_result = pm.cast(metric_result, dtype=pm.float64)
                res = (
                    pm.save(w_uri, w),
                    pm.save(metric_uri, metric_result),
                    pm.save(rsquared_uri, rsquared_result),
                )

            return res

        return my_comp, (x_owner, y_owner, model_owner, replicated_plc)

    def _linear_regression_eval(self, metric_name):
        linear_comp, _ = self._build_linear_regression_example(metric_name)

        x_data, y_data = generate_data(seed=42, n_instances=10, n_features=1)
        executors_storage = {
            "x-owner": {"x_data": x_data},
            "y-owner": {"y_data": y_data},
        }
        runtime = pm.LocalMooseRuntime(
            ["x-owner", "y-owner", "model-owner"],
            storage_mapping=executors_storage,
        )
        _ = runtime.evaluate_computation(
            computation=linear_comp,
            arguments={
                "x_uri": "x_data",
                "y_uri": "y_data",
                "w_uri": "regression_weights",
                "metric_uri": "metric_result",
                "rsquared_uri": "rsquared_result",
            },
        )
        print(
            "Done: \n",
            runtime.read_value_from_storage("model-owner", "regression_weights"),
        )

    def test_linear_regression_mse(self):
        self._linear_regression_eval("mse")

    @pytest.mark.slow
    def test_linear_regression_mape(self):
        self._linear_regression_eval("mape")


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Run example")
    parser.add_argument("--verbose", action="store_true")
    args = parser.parse_args()

    if args.verbose:
        get_logger().setLevel(level=logging.DEBUG)

    unittest.main()

四 缺陷

  • 配置机器为四台
  • 算子修改及协议修改可能性比较低
  • 配置脚本,及运行定义流程麻烦
  • 现有的文档较少,算子实现参考及用法不明确

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值