Skip to content

Commit

Permalink
demo: Add options for not encoding data before sending it to a model. (
Browse files Browse the repository at this point in the history
…#106)

* demo: to handle none encoder to resolve #104
* demo: Add disclaimers.
* demo/add: Reduce chunk sizes to make help avoid out of gas issues.
* demo/add/perceptron: Add features in order.
* demo: Improve some button sizing.
  • Loading branch information
juharris committed Oct 27, 2020
1 parent 2fc019b commit dfcbe24
Show file tree
Hide file tree
Showing 17 changed files with 225 additions and 128 deletions.
2 changes: 1 addition & 1 deletion demo/client/migrations/2_deploy_sentiment_classifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ module.exports = async function (deployer) {
const numWordsPerUpdate = 250;

console.log(`Deploying IMDB model with ${weights.length} weights.`);
const intercept = convertNum(model.bias, web3, toFloat);
const intercept = convertNum(model.intercept || model.bias, web3, toFloat);
const learningRate = convertNum(0.5, web3, toFloat);

console.log(`Deploying DataHandler.`);
Expand Down
2 changes: 1 addition & 1 deletion demo/client/migrations/4_deploy_hot_dog_classifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ module.exports = function (deployer) {
// Information to persist to the database.
const name = "Hot Dog Classifier"
const description = "Classifies pictures as hot dog or not hot dog."
const encoder = 'MobileNetv2'
const encoder = 'MobileNetV2'
const modelInfo = {
name,
description,
Expand Down
2 changes: 1 addition & 1 deletion demo/client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "decai-demo-client",
"version": "1.4.0",
"version": "1.3.0",
"license": "MIT",
"private": true,
"proxy": "http://localhost:5387/",
Expand Down
1 change: 0 additions & 1 deletion demo/client/src/Footer.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ class Footer extends React.Component {
return (
<footer className={classes.footer}>
<Typography variant="subtitle1" color="textSecondary" align="center">
{/* TODO Make sure CELA validates this text. */}
⚠ WARNING Uploaded models and data used to train models are added to a decentralized public blockchain not controlled by Microsoft. We strongly encourage not training models using data with personally identifiable information.
Learn more <Link href='/about'>here</Link>.
</Typography>
Expand Down
7 changes: 5 additions & 2 deletions demo/client/src/components/About.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,17 @@ class About extends React.Component {
</Typography>
<Typography className={classes.section} component="p">
If you have not changed the default blockchain network in your browser's or extension's settings, then it is likely set to use the public Ethereum mainnet.
Microsoft does not fully endorse nor support the use of the mainnet or any other third party network because all information in it is public.
Microsoft does not fully endorse nor support the use of the mainnet or any other third party network because all information in it is public and might be difficult to completely delete.
</Typography>
<Typography className={classes.sectionTitle} variant="h5" component="h5">
<Link color='inherit' href='#project' name='project'>About This Project</Link>
</Typography>
<Typography className={classes.section} component="p">
The goal of this project is to promote sharing machine learning models at a greater scale.
To achieve this, we store model on a blockchain and allow people to update the models by providing their own data to a smart contracts which train the model.
To achieve this, models are stored on a blockchain and so that people can update the models by providing their own data to smart contracts which train the model.
Since this project could involve interacting with public blockchains, it is strongly encouraged that personal data is not used when interacting with models.
This project is meant to be a proof of concept.
For greater privacy and control over data, a private and permissioned chain can be used by trusted collaborators.
An overview of the project can be found in our <Link href='https://aka.ms/0xDeCA10B-blog1' target="_blank">blog post</Link>.
</Typography>
<Typography className={classes.sectionTitle} variant="h5" component="h5">
Expand Down
41 changes: 16 additions & 25 deletions demo/client/src/components/addDeployedModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ import ClearIcon from '@material-ui/icons/Clear';
import { withSnackbar } from 'notistack';
import PropTypes from 'prop-types';
import React from 'react';
import { ContractLoader } from '../contracts/loader';
import { Encoder } from '../encoding/encoder';
import { getNetworkType, getWeb3 } from '../getWeb3';
import { OnlineSafetyValidator } from '../safety/validator';
import { ModelInformation } from '../storage/data-store';
import { DataStoreFactory } from '../storage/data-store-factory';
import { ContractLoader } from '../contracts/loader';
import { checkStorages, renderStorageSelector } from './storageSelector';

const styles = theme => ({
Expand Down Expand Up @@ -80,7 +81,7 @@ class AddDeployedModel extends React.Component {
name: undefined,
description: undefined,
modelType: 'Classifier64',
encoder: 'none',
encoder: undefined,
storageType,
permittedStorageTypes: [],
}
Expand Down Expand Up @@ -135,7 +136,6 @@ class AddDeployedModel extends React.Component {

validateContract() {
this.setState({
checkedContentRestriction: false,
restrictContent: undefined,
isValid: undefined,
validatingContract: true,
Expand Down Expand Up @@ -178,7 +178,6 @@ class AddDeployedModel extends React.Component {
})
}
this.setState({
checkedContentRestriction: true,
restrictContent,
isValid: true,
validatingContract: false,
Expand Down Expand Up @@ -236,7 +235,7 @@ class AddDeployedModel extends React.Component {
List a deployed model
</Typography>
<Typography component="p">
Provide the address for the entry point contract.
Provide the address for the entry point contract that has already been deployed to a blockchain.
Then you will be prompted for other information about the contract.
</Typography>
<form className={this.classes.container} noValidate autoComplete="off">
Expand Down Expand Up @@ -288,20 +287,15 @@ class AddDeployedModel extends React.Component {
>
<MenuItem value={"Classifier64"}>Classifier64</MenuItem>
</Select>
<InputLabel className={this.classes.selectorLabel} htmlFor="encoder">Encoder</InputLabel>
<Select className={this.classes.selector}
onChange={this.handleInputChange}
value={this.state.encoder}
inputProps={{
name: 'encoder',
}}
disabled={!this.state.isValid}
>
<MenuItem value={"none"}>None</MenuItem>
<MenuItem value={"IMDB vocab"}>IMDB vocab (for English text)</MenuItem>
<MenuItem value={"universal sentence encoder"}>Universal Sentence Encoder (for English text)</MenuItem>
<MenuItem value={"MobileNetv2"}>MobileNetv2 (for images)</MenuItem>
</Select>

{(this.state.restrictContent === false || Object.values(Encoder).indexOf(this.state.encoder) > -1) && <div>
<Typography variant="h6" component="h6">
Encoder: {this.state.encoder}
</Typography>
<Typography component="p">
An encoder is the method that is used to convert the input (text, image, etc.) into a machine readable format.
</Typography>
</div>}
</div>
</form>
<Button className={this.classes.button} variant="outlined" color="primary" onClick={this.save}
Expand All @@ -315,8 +309,7 @@ class AddDeployedModel extends React.Component {
}

async save() {
const { address, name, description, modelType, encoder } = this.state;
const modelInfo = new ModelInformation({ name, address, description, modelType, encoder })
const { address, name, description, modelType } = this.state;

// Validate
if (!name) {
Expand All @@ -327,10 +320,8 @@ class AddDeployedModel extends React.Component {
this.notify("You must select model type", { variant: 'error' });
return
}
if (encoder === undefined) {
this.notify("You must select an encoder", { variant: 'error' });
return
}

const modelInfo = new ModelInformation({ name, address, description, modelType })

// Save to a database.
const storage = this.storages[this.state.storageType];
Expand Down
98 changes: 59 additions & 39 deletions demo/client/src/components/addModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import CollaborativeTrainer64 from '../contracts/compiled/CollaborativeTrainer64
import DataHandler64 from '../contracts/compiled/DataHandler64.json';
import Points64 from '../contracts/compiled/Points64.json';
import Stakeable64 from '../contracts/compiled/Stakeable64.json';
import { Encoder } from '../encoding/encoder';
import { getNetworkType, getWeb3 } from '../getWeb3';
import { ModelDeployer } from '../ml-models/deploy-model';
import { ModelInformation } from '../storage/data-store';
Expand All @@ -45,6 +46,7 @@ const styles = theme => ({
},
button: {
marginTop: 20,
alignSelf: 'start',
},
selectorLabel: {
marginTop: 8,
Expand Down Expand Up @@ -86,7 +88,7 @@ class AddModel extends React.Component {
toFloat: 1E9,
modelType: 'Classifier64',
modelFileName: undefined,
encoder: 'none',
encoder: Encoder.None,
incentiveMechanism: 'Points64',
refundTimeWaitTimeS: 0,
ownerClaimWaitTimeS: 0,
Expand Down Expand Up @@ -229,13 +231,13 @@ class AddModel extends React.Component {
return "A model file must be uploaded"
}
if (!(this.state.refundTimeWaitTimeS <= this.state.ownerClaimWaitTimeS)) {
return "The refund/reward wait time must be at most the owner wait time"
return "The owner wait time must greater than or equal to the refund/reward wait time"
}
if (!(this.state.ownerClaimWaitTimeS <= this.state.anyAddressClaimWaitTimeS)) {
return "The owner wait time must be at most the full deposit take wait time"
return "The full deposit take wait time greather than or equal to the owner wait time"
}
if (this.state.costWeight < 0) {
return "The deposit wait must be at least 0"
return "The deposit wait must be greater than or equal to 0"
}
return null
}
Expand All @@ -256,9 +258,15 @@ class AddModel extends React.Component {
<Typography component="p">
If you want to use a model that is already deployed, then you can add its information <Link href='/addDeployedModel'>here</Link>.
</Typography>
<Typography component="p">
⚠ WARNING When you click/tap on the SAVE button, transactions will be created for you to approve in your browser's tool (e.g. MetaMask).
If the transactions are approved, you might be sending data to a public dencentralized blockchain not controlled by Microsoft.
Before approving, you should understand the implications of interacting with a public blockchain.
You can learn more <Link href='/about' target='_blank'>here</Link>.
</Typography>

<form className={this.classes.container} noValidate autoComplete="off">
<div className={this.classes.form} >
<div className={this.classes.form}>
<TextField
name="name"
label="Model name"
Expand Down Expand Up @@ -288,25 +296,29 @@ class AddModel extends React.Component {
name: 'encoder',
}}
>
<Tooltip value="none" placement="top-start"
title="No transformation will be applied">
<MenuItem>None</MenuItem>
<Tooltip value={Encoder.None} placement="top-start"
title="No transformation will be applied (except for whatever is required to send the data to the contract such as converting to hexadecimal)">
<MenuItem>None (for raw integer data)</MenuItem>
</Tooltip>
<Tooltip value={Encoder.Mult1E9Round} placement="top-start"
title="Each number will be multiplied by 10^9 and then rounded since smart contracts use integers instead of decimal numbers">
<MenuItem>Multiply by 10^9, then round (for raw decimal numbers)</MenuItem>
</Tooltip>
<Tooltip value="MurmurHash3" placement="top-start"
title="Convert each word to a 32-bit number using MurmurHash3">
<MenuItem>MurmurHash3</MenuItem>
<Tooltip value={Encoder.MurmurHash3} placement="top-start"
title="Convert each word to a 32-bit number using MurmurHash3. Separates word using spaces.">
<MenuItem>MurmurHash3 (for text with sparse models)</MenuItem>
</Tooltip>
<Tooltip value="IMDB vocab" placement="top-start"
<Tooltip value={Encoder.ImdbVocab} placement="top-start"
title="Convert each word in English text to a number using the 1000 most frequent words in the IMDB review dataset">
<MenuItem>IMDB vocab</MenuItem>
<MenuItem>IMDB vocab (for a limited set of English text)</MenuItem>
</Tooltip>
<Tooltip value="universal sentence encoder" placement="top-start"
title="Use Universal Sentence Encoder to convert English text to a vector of numbers">
<MenuItem>Universal Sentence Encoder (for English text)</MenuItem>
<Tooltip value={Encoder.USE} placement="top-start"
title="Use the Universal Sentence Encoder to convert English text to a vector of numbers">
<MenuItem>Universal Sentence Encoder (for English text with dense models)</MenuItem>
</Tooltip>
<Tooltip value="MobileNetv2" placement="top-start"
title="Use MobileNetv2 to convert images to a vector of numbers">
<MenuItem>MobileNetv2 (for images)</MenuItem>
<Tooltip value={Encoder.MobileNetV2} placement="top-start"
title="Use MobileNetV2 to convert images to a vector of numbers">
<MenuItem>MobileNetV2 (for images with dense models)</MenuItem>
</Tooltip>
</Select>

Expand Down Expand Up @@ -372,24 +384,31 @@ class AddModel extends React.Component {
}

{/* Storage */}
<Typography variant="h6" component="h6">
Model Meta-data Storage
</Typography>
<Typography component="p">
When you click the save button below, you will be prompted to store your model on a blockchain.
In the next selection dropdown, you can choose if you want to store meta-data for this model so that you can easily find it using this demo website.
</Typography>
<div className={this.classes.selector}>
{renderStorageSelector("Where to store the supplied meta-data about this model like its address",
this.state.storageType, this.handleInputChange, this.state.permittedStorageTypes)}
</div>
{this.state.networkType === 'main' && <Typography component="p">
{"⚠ You are currently set up to deploy to a main network. Please consider deploying to a test network before deploying to a main network. "}
</Typography>}

{disableReason !== null && <Typography component="p">
{disableReason}
</Typography>}
<Button className={this.classes.button} variant="outlined" color="primary" onClick={this.save}
disabled={disableReason !== null}
>
Save
</Button>
</div>
</form>
{this.state.networkType === 'main' && <Typography component="p">
{"⚠ You are currently set up to deploy to a main network. Please consider deploying to a test network before deploying to a main network. "}
</Typography>}

{disableReason !== null && <Typography component="p">
{disableReason}
</Typography>}
<Button className={this.classes.button} variant="outlined" color="primary" onClick={this.save}
disabled={disableReason !== null}
>
Save
</Button>
</Paper>
<Paper className={this.classes.root} elevation={1}>
<Typography component="h3">
Expand Down Expand Up @@ -524,22 +543,23 @@ class AddModel extends React.Component {
}
const account = accounts[0];

const [dataHandler, incentiveMechanism, model] = await Promise.all([
// Deploy the model first since it is more likely something will go wrong with deploying it compared to the other contracts.
const model = await this.deployer.deployModel(this.state.model, {
account,
toFloat: this.state.toFloat,
notify: this.notify, dismissNotification: this.dismissNotification,
saveTransactionHash: this.saveTransactionHash, saveAddress: this.saveAddress,
})

const [dataHandler, incentiveMechanism] = await Promise.all([
this.deployDataHandler(account),
this.deployIncentiveMechanism(account),
this.deployer.deployModel(this.state.model, {
account,
toFloat: this.state.toFloat,
notify: this.notify, dismissNotification: this.dismissNotification,
saveTransactionHash: this.saveTransactionHash, saveAddress: this.saveAddress,
}),
]);

const mainContract = await this.deployMainEntryPoint(account, dataHandler, incentiveMechanism, model);

modelInfo.address = mainContract.options.address;


if (this.state.storageType !== 'none') {
// Save to a database.
const storage = this.storages[this.state.storageType];
Expand Down
Loading

0 comments on commit dfcbe24

Please sign in to comment.