UnityGiles commited on
Commit
4a6db11
·
1 Parent(s): 522203e

update to inference-engine

Browse files
MiniLMv6.sentis DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:c9a2597ce9edce4c09b32e993b7f906cce91fceb2f461a597b974f71ee70453d
3
- size 90898400
 
 
 
 
README.md CHANGED
@@ -2,36 +2,24 @@
2
  license: apache-2.0
3
  library_name: unity-sentis
4
  pipeline_tag: sentence-similarity
 
 
5
  ---
6
 
7
- # Mini LM Sentis Similarity validated for Unity Sentis (Version 1.4.0-pre.2*)
8
- *Version 1.3.0 Sentis files are not compatible with Sentis 1.4.0 and need to be recreated/downloaded
9
 
10
- This is the [Mini LM v6 model](https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2) in the Sentis format to run on Unity 2023. It is a sentence similarity model that compares different sentences and gives a score depending on how similar they are.
11
 
12
  ## How to Use
13
 
14
- * Create a new scene in Unity 2023
15
- * Install com.unity.sentis from the package manager
16
- * Add the MiniLMv6.cs file to the Main Camera
17
- * Add vocab.txt and MiniLMv6.sentis to the Assets/StreamingAssets folder
18
- * Change the string1 and string2 variables to the desired strings
19
- * Press play, the results will show in the Console
20
 
21
- ## Project Demonstration
22
- Thomas, a member of the Hugging Face team, also a good [tutorial](https://thomassimonini.substack.com/p/create-an-ai-robot-npc-using-hugging) of using this model in a mini-game made.
23
 
24
- # Example Inputs
25
- ```
26
- string1 = "That is a happy person"
27
-
28
- string2 = "That is a happy dog"
29
- ```
30
-
31
- # Example Outputs
32
- ```
33
- Similarity Score: 0.6945773
34
- ```
35
-
36
- ## Unity Sentis
37
- Sentis is the inference engine for Unity. More can be found about it [here](https://unity.com/products/sentis)
 
2
  license: apache-2.0
3
  library_name: unity-sentis
4
  pipeline_tag: sentence-similarity
5
+ tags:
6
+ - unity-inference-engine
7
  ---
8
 
9
+ # Mini LM in Unity 6 with Inference Engine
 
10
 
11
+ This is the [Mini LM v6 model](https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2) model running in Unity 6 with Inference Engine. Mini LM is a sentence similarity model that compares different sentences and gives a score depending on how similar they are.
12
 
13
  ## How to Use
14
 
15
+ * Create a new scene in Unity 6;
16
+ * Install `com.unity.ai.inference` from the package manager;
17
+ * Add the `RunMiniLM.cs` script to the Main Camera;
18
+ * Drag the `MiniLMv6.onnx` asset from the `models` folder into the `Model Asset` field;
19
+ * Drag the `vocab.txt` asset from the `data` folder into the `Vocab Asset` field;
 
20
 
21
+ ## Preview
22
+ Enter play mode. If working correctly the sentence similarity score will be logged to the console.
23
 
24
+ ## Inference Engine
25
+ Inference Engine is a neural network inference library for Unity. Find out more [here](https://docs.unity3d.com/Packages/com.unity.ai.inference@latest).
 
 
 
 
 
 
 
 
 
 
 
 
MiniLMv6.cs → RunMiniLM.cs RENAMED
@@ -1,51 +1,35 @@
1
- using System.Collections.Generic;
 
 
2
  using UnityEngine;
3
- using Unity.Sentis;
4
- using System.IO;
5
- using System.Text;
6
- using FF = Unity.Sentis.Functional;
7
-
8
- /*
9
- * Tiny Stories Inference Code
10
- * ===========================
11
- *
12
- * Put this script on the Main Camera
13
- *
14
- * In Assets/StreamingAssets put:
15
- *
16
- * MiniLMv6.sentis
17
- * vocab.txt
18
- *
19
- * Install package com.unity.sentis
20
- *
21
- */
22
-
23
-
24
- public class MiniLM : MonoBehaviour
25
  {
 
 
26
  const BackendType backend = BackendType.GPUCompute;
27
 
28
- string string1 = "That is a happy person"; // similarity = 1
29
 
30
- //Choose a string to comapre string1 to:
31
- string string2 = "That is a happy dog"; // similarity = 0.695
32
- //string string2 = "That is a very happy person"; // similarity = 0.943
33
- //string string2 = "Today is a sunny day"; // similarity = 0.257
34
 
35
  //Special tokens
36
- const int START_TOKEN = 101;
37
- const int END_TOKEN = 102;
38
 
39
  //Store the vocabulary
40
  string[] tokens;
41
 
42
  const int FEATURES = 384; //size of feature space
43
 
44
- IWorker engine, dotScore;
45
 
46
  void Start()
47
  {
48
- tokens = File.ReadAllLines(Application.streamingAssetsPath + "/vocab.txt");
49
 
50
  engine = CreateMLModel();
51
 
@@ -54,87 +38,70 @@ public class MiniLM : MonoBehaviour
54
  var tokens1 = GetTokens(string1);
55
  var tokens2 = GetTokens(string2);
56
 
57
- using TensorFloat embedding1 = GetEmbedding(tokens1);
58
- using TensorFloat embedding2 = GetEmbedding(tokens2);
59
 
60
  float score = GetDotScore(embedding1, embedding2);
61
 
62
  Debug.Log("Similarity Score: " + score);
63
  }
64
 
65
- float GetDotScore(TensorFloat A, TensorFloat B)
66
  {
67
- var inputs = new Dictionary<string, Tensor>()
68
- {
69
- { "input_0", A },
70
- { "input_1", B }
71
- };
72
- dotScore.Execute(inputs);
73
- var output = dotScore.PeekOutput() as TensorFloat;
74
- output.CompleteOperationsAndDownload();
75
  return output[0];
76
  }
77
 
78
- TensorFloat GetEmbedding(List<int> tokens)
79
  {
80
- int N = tokens.Count;
81
- using var input_ids = new TensorInt(new TensorShape(1, N), tokens.ToArray());
82
- using var token_type_ids = new TensorInt(new TensorShape(1, N), new int[N]);
83
  int[] mask = new int[N];
84
  for (int i = 0; i < mask.Length; i++)
85
  {
86
  mask[i] = 1;
87
  }
88
- using var attention_mask = new TensorInt(new TensorShape(1, N), mask);
89
 
90
- var inputs = new Dictionary<string, Tensor>
91
- {
92
- {"input_0", input_ids },
93
- {"input_1", attention_mask },
94
- {"input_2", token_type_ids}
95
- };
96
 
97
- engine.Execute(inputs);
98
-
99
- var output = engine.TakeOutputOwnership("output_0") as TensorFloat;
100
  return output;
101
  }
102
 
103
- IWorker CreateMLModel()
104
  {
105
- Model model = ModelLoader.Load(Application.streamingAssetsPath + "/MiniLMv6.sentis");
106
-
107
- Model modelWithMeanPooling = Functional.Compile(
108
- (input_ids, attention_mask, token_type_ids) =>
109
- {
110
- var tokenEmbeddings = model.Forward(input_ids, attention_mask, token_type_ids)[0];
111
- return MeanPooling(tokenEmbeddings, attention_mask);
112
- },
113
- (model.inputs[0], model.inputs[1], model.inputs[2])
114
- );
115
-
116
- return WorkerFactory.CreateWorker(backend, modelWithMeanPooling);
117
  }
118
 
119
  //Get average of token embeddings taking into account the attention mask
120
  FunctionalTensor MeanPooling(FunctionalTensor tokenEmbeddings, FunctionalTensor attentionMask)
121
  {
122
- var mask = attentionMask.Unsqueeze(-1).BroadcastTo(new[] { FEATURES }); //shape=(1,N,FEATURES)
123
- var A = FF.ReduceSum(tokenEmbeddings * mask, 1, false); //shape=(1,FEATURES)
124
- var B = A / (FF.ReduceSum(mask, 1, false) + 1e-9f); //shape=(1,FEATURES)
125
- var C = FF.Sqrt(FF.ReduceSum(FF.Square(B), 1, true)); //shape=(1,FEATURES)
126
- return B / C; //shape=(1,FEATURES)
127
  }
128
 
129
- IWorker CreateDotScoreModel()
130
  {
131
- Model dotScoreModel = Functional.Compile(
132
- (input1, input2) => Functional.ReduceSum(input1 * input2, 1),
133
- (InputDef.Float(new TensorShape(1, FEATURES)),
134
- InputDef.Float(new TensorShape(1, FEATURES)))
135
- );
136
-
137
- return WorkerFactory.CreateWorker(backend, dotScoreModel);
138
  }
139
 
140
  List<int> GetTokens(string text)
@@ -152,10 +119,10 @@ public class MiniLM : MonoBehaviour
152
  foreach (var word in words)
153
  {
154
  int start = 0;
155
- for(int i = word.Length; i >= 0;i--)
156
  {
157
- string subword = start == 0 ? word.Substring(start, i) : "##" + word.Substring(start, i-start);
158
- int index = System.Array.IndexOf(tokens, subword);
159
  if (index >= 0)
160
  {
161
  ids.Add(index);
@@ -169,15 +136,14 @@ public class MiniLM : MonoBehaviour
169
 
170
  ids.Add(END_TOKEN);
171
 
172
- Debug.Log("Tokenized sentece = " + s);
173
 
174
  return ids;
175
  }
176
 
177
- private void OnDestroy()
178
- {
179
  dotScore?.Dispose();
180
  engine?.Dispose();
181
  }
182
-
183
  }
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+ using Unity.InferenceEngine;
4
  using UnityEngine;
5
+
6
+ public class RunMiniLM : MonoBehaviour
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  {
8
+ public ModelAsset modelAsset;
9
+ public TextAsset vocabAsset;
10
  const BackendType backend = BackendType.GPUCompute;
11
 
12
+ string string1 = "That is a happy person"; // similarity = 1
13
 
14
+ //Choose a string to compare with string1:
15
+ string string2 = "That is a happy dog"; // similarity = 0.695
16
+ //string string2 = "That is a very happy person"; // similarity = 0.943
17
+ //string string2 = "Today is a sunny day"; // similarity = 0.257
18
 
19
  //Special tokens
20
+ const int START_TOKEN = 101;
21
+ const int END_TOKEN = 102;
22
 
23
  //Store the vocabulary
24
  string[] tokens;
25
 
26
  const int FEATURES = 384; //size of feature space
27
 
28
+ Worker engine, dotScore;
29
 
30
  void Start()
31
  {
32
+ tokens = vocabAsset.text.Split("\r\n");
33
 
34
  engine = CreateMLModel();
35
 
 
38
  var tokens1 = GetTokens(string1);
39
  var tokens2 = GetTokens(string2);
40
 
41
+ using Tensor<float> embedding1 = GetEmbedding(tokens1);
42
+ using Tensor<float> embedding2 = GetEmbedding(tokens2);
43
 
44
  float score = GetDotScore(embedding1, embedding2);
45
 
46
  Debug.Log("Similarity Score: " + score);
47
  }
48
 
49
+ float GetDotScore(Tensor<float> A, Tensor<float> B)
50
  {
51
+ dotScore.Schedule(A, B);
52
+ var output = (dotScore.PeekOutput() as Tensor<float>).DownloadToNativeArray();
 
 
 
 
 
 
53
  return output[0];
54
  }
55
 
56
+ Tensor<float> GetEmbedding(List<int> tokenList)
57
  {
58
+ int N = tokenList.Count;
59
+ using var input_ids = new Tensor<int>(new TensorShape(1, N), tokenList.ToArray());
60
+ using var token_type_ids = new Tensor<int>(new TensorShape(1, N), new int[N]);
61
  int[] mask = new int[N];
62
  for (int i = 0; i < mask.Length; i++)
63
  {
64
  mask[i] = 1;
65
  }
66
+ using var attention_mask = new Tensor<int>(new TensorShape(1, N), mask);
67
 
68
+ engine.Schedule(input_ids, attention_mask, token_type_ids);
 
 
 
 
 
69
 
70
+ var output = engine.PeekOutput().ReadbackAndClone() as Tensor<float>;
 
 
71
  return output;
72
  }
73
 
74
+ Worker CreateMLModel()
75
  {
76
+ var model = ModelLoader.Load(modelAsset);
77
+ var graph = new FunctionalGraph();
78
+ var inputs = graph.AddInputs(model);
79
+ var tokenEmbeddings = Functional.Forward(model, inputs)[0];
80
+ var attention_mask = inputs[1];
81
+ var output = MeanPooling(tokenEmbeddings, attention_mask);
82
+ var modelWithMeanPooling = graph.Compile(output);
83
+
84
+ return new Worker(modelWithMeanPooling, backend);
 
 
 
85
  }
86
 
87
  //Get average of token embeddings taking into account the attention mask
88
  FunctionalTensor MeanPooling(FunctionalTensor tokenEmbeddings, FunctionalTensor attentionMask)
89
  {
90
+ var mask = attentionMask.Unsqueeze(-1).BroadcastTo(new[] { FEATURES }); //shape=(1,N,FEATURES)
91
+ var A = Functional.ReduceSum(tokenEmbeddings * mask, 1); //shape=(1,FEATURES)
92
+ var B = A / (Functional.ReduceSum(mask, 1) + 1e-9f); //shape=(1,FEATURES)
93
+ var C = Functional.Sqrt(Functional.ReduceSum(Functional.Square(B), 1, true)); //shape=(1,FEATURES)
94
+ return B / C; //shape=(1,FEATURES)
95
  }
96
 
97
+ Worker CreateDotScoreModel()
98
  {
99
+ var graph = new FunctionalGraph();
100
+ var input1 = graph.AddInput<float>(new TensorShape(1, FEATURES));
101
+ var input2 = graph.AddInput<float>(new TensorShape(1, FEATURES));
102
+ var output = Functional.ReduceSum(input1 * input2, 1);
103
+ var dotScoreModel = graph.Compile(output);
104
+ return new Worker(dotScoreModel, backend);
 
105
  }
106
 
107
  List<int> GetTokens(string text)
 
119
  foreach (var word in words)
120
  {
121
  int start = 0;
122
+ for (int i = word.Length; i >= 0; i--)
123
  {
124
+ string subword = start == 0 ? word.Substring(start, i) : "##" + word.Substring(start, i - start);
125
+ int index = Array.IndexOf(tokens, subword);
126
  if (index >= 0)
127
  {
128
  ids.Add(index);
 
136
 
137
  ids.Add(END_TOKEN);
138
 
139
+ Debug.Log("Tokenized sentence = " + s);
140
 
141
  return ids;
142
  }
143
 
144
+ void OnDestroy()
145
+ {
146
  dotScore?.Dispose();
147
  engine?.Dispose();
148
  }
 
149
  }
vocab.txt → data/vocab.txt RENAMED
File without changes
info.json CHANGED
@@ -1,14 +1,14 @@
1
  {
2
  "code": [
3
- "MiniLMv6.cs"
4
  ],
5
  "models": [
6
- "MiniLMv6.sentis"
7
  ],
8
  "data": [
9
- "vocab.txt"
10
  ],
11
  "version": [
12
- "1.4.0"
13
  ]
14
  }
 
1
  {
2
  "code": [
3
+ "RunMiniLM.cs"
4
  ],
5
  "models": [
6
+ "models/MiniLMv6.onnx"
7
  ],
8
  "data": [
9
+ "data/vocab.txt"
10
  ],
11
  "version": [
12
+ "2.2.0"
13
  ]
14
  }
MiniLMv6.onnx → models/MiniLMv6.onnx RENAMED
File without changes