Paul Bird commited on
Commit
9be3f67
1 Parent(s): ea0d653

Upload 7 files

Browse files
Files changed (7) hide show
  1. RunAutomata.cs +274 -0
  2. lizard.onnx +3 -0
  3. lizard.sentis +0 -0
  4. poop.onnx +3 -0
  5. poop.sentis +0 -0
  6. turtle.onnx +3 -0
  7. turtle.sentis +0 -0
RunAutomata.cs ADDED
@@ -0,0 +1,274 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System.Collections;
2
+ using System.Collections.Generic;
3
+ using UnityEngine;
4
+ using Unity.Sentis;
5
+ using System.IO;
6
+ using Lays = Unity.Sentis.Layers;
7
+
8
+ /*
9
+ * Neural Cellular Automata Inference Code
10
+ * =======================================
11
+ *
12
+ * Put this script on the Main Camera
13
+ * Create an image or quad in the scene.
14
+ * Assign an unlit transparent material to the image/quad.
15
+ * Draw the same material into the outputMaterial field
16
+ *
17
+ */
18
+ public class RunAutomata : MonoBehaviour
19
+ {
20
+ //Change this to load a different model:
21
+ public AutomataNames automataName = AutomataNames.Poop;
22
+
23
+ //Reduce this to make it run slower
24
+ [Range(0f, 1f)]
25
+ public float stepSize = 1.0f;
26
+
27
+ const BackendType backend = BackendType.GPUCompute;
28
+
29
+ //Drag your unlit transparent material here for drawing the output
30
+ public Material outputMaterial;
31
+
32
+ //optional material for average alpha
33
+ public Material avgAlphaMaterial;
34
+
35
+ public enum AutomataNames { Lizard, Turtle ,Poop};
36
+
37
+ //Model parameters
38
+ const int trainedResolution = 40;
39
+ const int trainedPool = 16;
40
+ const int alphaBlocks = 4;
41
+ int m_paddedImageSize;
42
+ int m_trainedHiddenStates;
43
+
44
+ //Workers to run the networks
45
+ private IWorker m_WorkerStateUpdate;
46
+ private IWorker m_WorkerClip;
47
+
48
+ private TensorFloat m_currentStateTensor;
49
+ private RenderTexture m_currentStateTexture;
50
+ private RenderTexture m_currentBlockAlphaStateTexture;
51
+
52
+ Ops m_ops;
53
+ ITensorAllocator m_allocator;
54
+
55
+ void Start()
56
+ {
57
+ m_allocator = new TensorCachingAllocator();
58
+ m_ops = WorkerFactory.CreateOps(backend, m_allocator);
59
+
60
+ Application.targetFrameRate = 60;
61
+
62
+ LoadAutomataModel();
63
+
64
+ CreateProcessingModel();
65
+
66
+ SetupState();
67
+
68
+ SetupTextures();
69
+
70
+ DrawDotAt(m_paddedImageSize / 2, m_paddedImageSize / 2);
71
+ }
72
+ void LoadAutomataModel() {
73
+
74
+ Model m_ModelStateUpdate = null;
75
+
76
+ switch (automataName) {
77
+ case AutomataNames.Lizard:
78
+ m_ModelStateUpdate = ModelLoader.Load(Application.streamingAssetsPath + "/lizard.sentis");
79
+ break;
80
+ case AutomataNames.Turtle:
81
+ m_ModelStateUpdate = ModelLoader.Load(Application.streamingAssetsPath + "/turtle.sentis");
82
+ break;
83
+ case AutomataNames.Poop:
84
+ m_ModelStateUpdate = ModelLoader.Load(Application.streamingAssetsPath + "/poop.sentis");
85
+ break;
86
+ }
87
+ m_trainedHiddenStates = m_ModelStateUpdate.inputs[0].shape[3].value;
88
+
89
+ m_paddedImageSize = trainedResolution + trainedPool * 2;
90
+
91
+ m_WorkerStateUpdate = WorkerFactory.CreateWorker(backend, m_ModelStateUpdate, false);
92
+
93
+ }
94
+ void CreateProcessingModel() {
95
+
96
+ var m_Model = new Model();
97
+
98
+ var input0 = new Model.Input
99
+ {
100
+ name = "input0",
101
+ shape = (new SymbolicTensorShape(1, m_trainedHiddenStates, m_paddedImageSize, m_paddedImageSize)),
102
+ dataType=DataType.Float
103
+ };
104
+
105
+ var input1 = new Model.Input
106
+ {
107
+ name = "input1",
108
+ shape = (new SymbolicTensorShape(1, m_trainedHiddenStates, m_paddedImageSize, m_paddedImageSize)),
109
+ dataType = DataType.Float
110
+ };
111
+
112
+ var inputStepSize = new Model.Input
113
+ {
114
+ name = "inputStepSize",
115
+ shape = new SymbolicTensorShape(1, 1, 1, 1),
116
+ dataType = DataType.Float
117
+ };
118
+
119
+ m_Model.inputs.Add(input0);
120
+ m_Model.inputs.Add(input1);
121
+ m_Model.inputs.Add(inputStepSize);
122
+
123
+ m_Model.AddConstant(new Lays.Constant("aliveRate", new TensorFloat(new TensorShape(1, 1, 1, 1), new[] { 0.1f })));
124
+
125
+ m_Model.AddConstant(new Lays.Constant("sliceStarts", new int[] { 0, 3, 0, 0 }));
126
+ m_Model.AddConstant(new Lays.Constant("sliceEnds", new[] { 1, 4 ,m_paddedImageSize, m_paddedImageSize }));
127
+
128
+ m_Model.AddLayer(new Lays.Slice("sliceI0", "input0", "sliceStarts", "sliceEnds"));
129
+ m_Model.AddLayer(new Lays.MaxPool("maxpool0", "sliceI0", new[] { 3, 3 }, new[] { 1, 1 }, new[] { 1, 1, 1, 1 }));
130
+ m_Model.AddLayer(new Lays.Greater("pre_life_mask", "maxpool0", "aliveRate")); //INT
131
+
132
+ m_Model.AddLayer(new Lays.Mul("input1_stepsize", "input1", "inputStepSize" ));
133
+
134
+ m_Model.AddLayer(new Lays.RandomUniform("random", new int[] { 1, 1, m_paddedImageSize, m_paddedImageSize}, 0.0f, 1.0f, 0));
135
+ m_Model.AddConstant(new Lays.Constant("fireRate", new TensorFloat(new TensorShape(1, 1, 1, 1), new[] { 0.5f })));
136
+ m_Model.AddLayer(new Lays.LessOrEqual("lessEqualFireRateINT", "random", "fireRate"));
137
+
138
+ m_Model.AddLayer(new Lays.Cast("lessEqualFireRate", "lessEqualFireRateINT", DataType.Float));
139
+
140
+ m_Model.AddLayer(new Lays.Mul("mul", "input1_stepsize", "lessEqualFireRate" ));
141
+
142
+ m_Model.AddLayer(new Lays.Add("add", "input0", "mul" ));
143
+
144
+ m_Model.AddLayer(new Lays.Slice("sliceI1", "add", "sliceStarts", "sliceEnds"));
145
+ m_Model.AddLayer(new Lays.MaxPool("maxpool1", "sliceI1", new [] { 3 ,3 }, new[] { 1, 1 }, new[] {1, 1, 1, 1}));
146
+ m_Model.AddLayer(new Lays.Greater("post_life_mask", "maxpool1", "aliveRate"));
147
+
148
+
149
+ m_Model.AddLayer(new Lays.And("andINT", "pre_life_mask", "post_life_mask"));
150
+ m_Model.AddLayer(new Lays.Cast("and", "andINT", DataType.Float));
151
+
152
+ m_Model.AddLayer(new Lays.Mul("outputState", "add", "and" ));
153
+
154
+ m_Model.AddConstant(new Lays.Constant("sliceStarts2", new[] { 0, 0, trainedPool, trainedPool }));
155
+ m_Model.AddConstant(new Lays.Constant("sliceEnds2", new[] { 1, 4, m_paddedImageSize - trainedPool, m_paddedImageSize - trainedPool }));
156
+
157
+ m_Model.AddLayer(new Lays.Slice("outputImage", "outputState", "sliceStarts2", "sliceEnds2"));
158
+
159
+ m_Model.AddLayer(new Lays.Slice("outputIC", "outputImage", "sliceStarts", "sliceEnds"));
160
+
161
+ int blockSize = trainedResolution / alphaBlocks;
162
+ m_Model.AddLayer(new Lays.AveragePool("avgPoolBlocks", "outputIC", new[] { blockSize, blockSize }, new[] { blockSize, blockSize }, new[] { 1, 1, 1, 1 }));
163
+
164
+ m_Model.outputs.Add("outputState");
165
+ m_Model.outputs.Add("outputImage");
166
+ m_Model.outputs.Add("avgPoolBlocks");
167
+
168
+ m_WorkerClip = WorkerFactory.CreateWorker(BackendType.GPUCompute, m_Model);
169
+
170
+ }
171
+
172
+ void SetupState()
173
+ {
174
+ float[] data = new float[1 * m_paddedImageSize * m_paddedImageSize * m_trainedHiddenStates];
175
+ m_currentStateTensor = new TensorFloat(new TensorShape(1, m_trainedHiddenStates, m_paddedImageSize, m_paddedImageSize), data);
176
+ }
177
+
178
+ void SetupTextures()
179
+ {
180
+ m_currentStateTexture = new RenderTexture(trainedResolution, trainedResolution, 0)
181
+ {
182
+ enableRandomWrite = true
183
+ };
184
+ outputMaterial.mainTexture = m_currentStateTexture;
185
+
186
+ if (avgAlphaMaterial)
187
+ {
188
+ m_currentBlockAlphaStateTexture = new RenderTexture(alphaBlocks, alphaBlocks, 0)
189
+ {
190
+ enableRandomWrite = true
191
+ };
192
+ outputMaterial.mainTexture = m_currentBlockAlphaStateTexture;
193
+ }
194
+ }
195
+
196
+ void DrawDotAt(int x,int y)
197
+ {
198
+ m_currentStateTensor.MakeReadable();
199
+
200
+ float[] data = m_currentStateTensor.ToReadOnlyArray();
201
+ for (int k = 3; k < 16; k++)
202
+ {
203
+ data[m_paddedImageSize * m_paddedImageSize * k + m_paddedImageSize * y + x] = 1f;
204
+ }
205
+ Replace(ref m_currentStateTensor, new TensorFloat(m_currentStateTensor.shape, data));
206
+ }
207
+
208
+ void Update()
209
+ {
210
+ DoInference();
211
+ if (Input.GetKeyDown(KeyCode.Escape))
212
+ {
213
+ Application.Quit();
214
+ }
215
+ if (Input.GetKeyDown(KeyCode.Space))
216
+ {
217
+ DrawDotAt(UnityEngine.Random.Range(0, m_paddedImageSize), UnityEngine.Random.Range(0, m_paddedImageSize));
218
+ }
219
+ }
220
+
221
+ void Replace(ref TensorFloat A, TensorFloat B)
222
+ {
223
+ A?.Dispose();
224
+ A = B;
225
+ }
226
+
227
+ void DoInference() {
228
+
229
+ using var stepSizeTensor = new TensorFloat(new TensorShape(1, 1, 1, 1), new float[] { stepSize });
230
+
231
+ using var currentStateTensorT = m_ops.Transpose(m_currentStateTensor, new int[] { 0, 2, 3, 1 });
232
+
233
+ m_WorkerStateUpdate.Execute(currentStateTensorT);
234
+ TensorFloat outputStateT = m_WorkerStateUpdate.PeekOutput() as TensorFloat;
235
+
236
+ using var outputState = m_ops.Transpose(outputStateT, new int[] { 0, 3, 1, 2 });
237
+
238
+ var inputs = new Dictionary<string, Tensor>() {
239
+ { "input0", m_currentStateTensor }, //float
240
+ { "input1", outputState }, //float
241
+ { "inputStepSize", stepSizeTensor } //float
242
+ };
243
+ m_WorkerClip.Execute(inputs);
244
+
245
+ TensorFloat clippedState = m_WorkerClip.PeekOutput("outputState") as TensorFloat;
246
+ TensorFloat outputImage = m_WorkerClip.PeekOutput("outputImage") as TensorFloat;
247
+ TensorFloat blockAvgAlphaState = m_WorkerClip.PeekOutput("avgPoolBlocks") as TensorFloat;
248
+
249
+ if (m_currentStateTexture)
250
+ {
251
+ TextureConverter.RenderToTexture(outputImage, m_currentStateTexture);
252
+ }
253
+
254
+ if (m_currentBlockAlphaStateTexture)
255
+ {
256
+ TextureConverter.RenderToTexture(blockAvgAlphaState, m_currentBlockAlphaStateTexture);
257
+ }
258
+
259
+ Replace(ref m_currentStateTensor, clippedState);
260
+ m_currentStateTensor.TakeOwnership();
261
+ }
262
+
263
+ void OnDestroy()
264
+ {
265
+ m_currentStateTensor.Dispose();
266
+
267
+ m_WorkerStateUpdate.Dispose();
268
+ m_WorkerClip.Dispose();
269
+
270
+ m_ops?.Dispose();
271
+ m_allocator?.Dispose();
272
+ }
273
+
274
+ }
lizard.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cfc3f2761a6c13c3985c5c2d4afdb8495c63916be0166708b6c8de5495301af9
3
+ size 62332
lizard.sentis ADDED
Binary file (67 kB). View file
 
poop.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3178f88f94defda03b83b33b8a9c6326edc16dfd496ad16e2705a5ac86be35ef
3
+ size 62330
poop.sentis ADDED
Binary file (67 kB). View file
 
turtle.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d64f01dd80339ec69bebe2db259cad36ed6d2f1fe7c5d5c12d3e309a6e877ee2
3
+ size 75209
turtle.sentis ADDED
Binary file (79.1 kB). View file