Skip to content

Commit 9ee3ff0

Browse files
Convenience Features (#5842)
* Added feature to training area replicator to optionally specify replications in builds only. * Add ModelCarousel component that cycles through a list of models to show training progress. * Add usage notes and fix default values * Added new config feature to distribute checkpointing evenly throughout training. * Dotnet formatting. * Updated docs. * Added tests. Co-authored-by: Jason Rupert <[email protected]>
1 parent 50d891e commit 9ee3ff0

File tree

12 files changed

+366
-13
lines changed

12 files changed

+366
-13
lines changed

Diff for: .github/workflows/nightly.yml

-3
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@ jobs:
1010
runs-on: ubuntu-latest
1111
steps:
1212
- uses: actions/checkout@v2
13-
with:
14-
token: ${{ secrets.GHE_ACCESS_TOKEN }}
15-
submodules: recursive
1613
- uses: actions/setup-python@v2
1714
- uses: actions/setup-node@v2
1815
with:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text.RegularExpressions;
4+
using TMPro;
5+
using Unity.Barracuda;
6+
using Unity.MLAgents;
7+
using Unity.MLAgents.Policies;
8+
using UnityEditor;
9+
#if UNITY_EDITOR
10+
using UnityEditor.Recorder;
11+
#endif
12+
using UnityEngine;
13+
14+
/**
15+
* Usage Notes:
16+
*
17+
* Add onnx models to the list and they will be played sequentially.
18+
* Create a recorder and a video of the sequence will be captured automatically if "Auto Record" is selected.
19+
* Recording only works in the Editor (not in standalone build)
20+
* Create a TextMeshPro Text GameObject and attach it to have the number of training steps of the current model shown.
21+
* To manually control transition between models choose a very large time, or "Pause" the system,
22+
* then use "Force Next" to advance.
23+
* "Reset" will start the sequence from the beginning again, use "Start" to proceed after resetting.
24+
* "Time Scale Override" can be set, "Seconds Between Switches" will decrease proportionally if you increase this
25+
* (i.e it represents simulated seconds between switches, not real time)
26+
*/
27+
28+
29+
public class ModelCarousel : MonoBehaviour
30+
{
31+
public bool m_Start = true;
32+
public bool m_Reset = false;
33+
public bool m_Pause = true;
34+
public bool m_ForceNext = false;
35+
public bool m_Loop = false;
36+
public bool m_AutoRecord = true;
37+
public bool m_ResetAgentOnModelChange = false;
38+
public int m_SecondsBetweenSwitches = 10;
39+
public float m_TimeScaleOverride = 0.0f;
40+
public List<NNModel> m_Models = new List<NNModel>();
41+
public bool m_ShowStepNumber = true;
42+
public int m_StepNumberRounding = 10000;
43+
44+
private int m_StepsSinceLastSwitch = 0;
45+
private int m_CurrentModelIndex = 0;
46+
private int m_CurrentlySetModelIndex = -1;
47+
48+
private NNModel m_OriginalModel = null;
49+
50+
private int k_FixedUpdatePerSecond;
51+
52+
// The attached Agent
53+
Agent m_Agent;
54+
55+
public TextMeshProUGUI textMeshComponent;
56+
57+
#if UNITY_EDITOR
58+
private RecorderWindow GetRecorderWindow()
59+
{
60+
return (RecorderWindow)EditorWindow.GetWindow(typeof(RecorderWindow));
61+
}
62+
#endif
63+
64+
private void Reset()
65+
{
66+
m_Reset = false;
67+
m_StepsSinceLastSwitch = 0;
68+
m_CurrentModelIndex = 0;
69+
m_Agent.SetModel(m_OriginalModel.name, m_OriginalModel);
70+
textMeshComponent?.SetText("Ready to Start");
71+
}
72+
73+
private void OnEnable()
74+
{
75+
m_Agent = GetComponent<Agent>();
76+
m_OriginalModel = m_Agent.GetComponent<BehaviorParameters>().Model;
77+
78+
Reset();
79+
80+
k_FixedUpdatePerSecond = (int)(1.0f / Time.fixedDeltaTime);
81+
82+
if (m_TimeScaleOverride > 0.0f)
83+
{
84+
Time.timeScale = m_TimeScaleOverride;
85+
}
86+
}
87+
88+
void StartRecording()
89+
{
90+
#if UNITY_EDITOR
91+
if (!m_AutoRecord)
92+
return;
93+
94+
Debug.Log("Starting Recording");
95+
RecorderWindow recorderWindow = GetRecorderWindow();
96+
if (!recorderWindow.IsRecording())
97+
recorderWindow.StartRecording();
98+
#endif
99+
}
100+
101+
void StopRecording()
102+
{
103+
#if UNITY_EDITOR
104+
if (!m_AutoRecord)
105+
return;
106+
107+
Debug.Log("Stopping Recording");
108+
RecorderWindow recorderWindow = GetRecorderWindow();
109+
if (recorderWindow.IsRecording())
110+
recorderWindow.StopRecording();
111+
#endif
112+
}
113+
114+
void UpdateStepNumberText()
115+
{
116+
if (!m_ShowStepNumber)
117+
return;
118+
119+
var result = Regex.Match(m_Models[m_CurrentModelIndex].name, @".*-(\d+)$");
120+
121+
string newText = "";
122+
if (result.Success && result.Groups.Count > 0)
123+
{
124+
var steps = Int32.Parse(result.Groups[1].Captures[0].Value);
125+
126+
int round = m_StepNumberRounding;
127+
steps += round / 2;
128+
steps /= round;
129+
steps *= round;
130+
131+
newText = $"After {steps:n0} steps";
132+
}
133+
134+
textMeshComponent?.SetText(newText);
135+
}
136+
137+
void SetModel()
138+
{
139+
if (m_CurrentModelIndex < 0 || m_CurrentModelIndex >= m_Models.Count)
140+
return;
141+
142+
m_Agent.SetModel(m_Models[m_CurrentModelIndex].name, m_Models[m_CurrentModelIndex]);
143+
m_CurrentlySetModelIndex = m_CurrentModelIndex;
144+
145+
UpdateStepNumberText();
146+
147+
if (m_ResetAgentOnModelChange)
148+
m_Agent.EndEpisode();
149+
}
150+
151+
void FixedUpdate()
152+
{
153+
if (m_Start)
154+
{
155+
m_Start = false;
156+
m_Pause = false;
157+
StartRecording();
158+
}
159+
160+
if (m_Reset)
161+
{
162+
StopRecording();
163+
Reset();
164+
m_Pause = true;
165+
m_Start = false;
166+
}
167+
168+
if (m_Pause && !m_ForceNext)
169+
return;
170+
171+
if (m_CurrentlySetModelIndex != m_CurrentModelIndex)
172+
{
173+
SetModel();
174+
}
175+
176+
m_StepsSinceLastSwitch++;
177+
178+
if (m_StepsSinceLastSwitch >= m_SecondsBetweenSwitches * k_FixedUpdatePerSecond || m_ForceNext)
179+
{
180+
m_ForceNext = false;
181+
m_StepsSinceLastSwitch = 0;
182+
m_CurrentModelIndex++;
183+
184+
if (m_CurrentModelIndex == m_Models.Count)
185+
{
186+
if (m_Loop)
187+
{
188+
m_CurrentModelIndex = 0;
189+
}
190+
else
191+
{
192+
Application.Quit(0);
193+
#if UNITY_EDITOR
194+
EditorApplication.isPlaying = false;
195+
#endif
196+
return;
197+
}
198+
}
199+
200+
SetModel();
201+
}
202+
}
203+
}

Diff for: Project/Assets/ML-Agents/Examples/SharedAssets/Scripts/ModelCarousel.cs.meta

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: Project/Packages/manifest.json

+2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
"com.unity.ml-agents": "file:../../com.unity.ml-agents",
66
"com.unity.ml-agents.extensions": "file:../../com.unity.ml-agents.extensions",
77
"com.unity.nuget.newtonsoft-json": "2.0.0",
8+
"com.unity.recorder": "3.0.3",
89
"com.unity.test-framework": "1.1.29",
10+
"com.unity.textmeshpro": "3.0.6",
911
"com.unity.toolchain.macos-x86_64-linux-x86_64": "2.0.3",
1012
"com.unity.ugui": "1.0.0",
1113
"com.unity.modules.imageconversion": "1.0.0",

Diff for: Project/Packages/packages-lock.json

+57
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,15 @@
7676
"dependencies": {},
7777
"url": "https://packages.unity.com"
7878
},
79+
"com.unity.recorder": {
80+
"version": "3.0.3",
81+
"depth": 0,
82+
"source": "registry",
83+
"dependencies": {
84+
"com.unity.timeline": "1.0.0"
85+
},
86+
"url": "https://packages.unity.com"
87+
},
7988
"com.unity.sysroot": {
8089
"version": "2.0.4",
8190
"depth": 1,
@@ -103,6 +112,27 @@
103112
},
104113
"url": "https://packages.unity.com"
105114
},
115+
"com.unity.textmeshpro": {
116+
"version": "3.0.6",
117+
"depth": 0,
118+
"source": "registry",
119+
"dependencies": {
120+
"com.unity.ugui": "1.0.0"
121+
},
122+
"url": "https://packages.unity.com"
123+
},
124+
"com.unity.timeline": {
125+
"version": "1.6.4",
126+
"depth": 1,
127+
"source": "registry",
128+
"dependencies": {
129+
"com.unity.modules.director": "1.0.0",
130+
"com.unity.modules.animation": "1.0.0",
131+
"com.unity.modules.audio": "1.0.0",
132+
"com.unity.modules.particlesystem": "1.0.0"
133+
},
134+
"url": "https://packages.unity.com"
135+
},
106136
"com.unity.toolchain.macos-x86_64-linux-x86_64": {
107137
"version": "2.0.3",
108138
"depth": 0,
@@ -122,6 +152,27 @@
122152
"com.unity.modules.imgui": "1.0.0"
123153
}
124154
},
155+
"com.unity.modules.animation": {
156+
"version": "1.0.0",
157+
"depth": 2,
158+
"source": "builtin",
159+
"dependencies": {}
160+
},
161+
"com.unity.modules.audio": {
162+
"version": "1.0.0",
163+
"depth": 2,
164+
"source": "builtin",
165+
"dependencies": {}
166+
},
167+
"com.unity.modules.director": {
168+
"version": "1.0.0",
169+
"depth": 2,
170+
"source": "builtin",
171+
"dependencies": {
172+
"com.unity.modules.audio": "1.0.0",
173+
"com.unity.modules.animation": "1.0.0"
174+
}
175+
},
125176
"com.unity.modules.imageconversion": {
126177
"version": "1.0.0",
127178
"depth": 0,
@@ -140,6 +191,12 @@
140191
"source": "builtin",
141192
"dependencies": {}
142193
},
194+
"com.unity.modules.particlesystem": {
195+
"version": "1.0.0",
196+
"depth": 2,
197+
"source": "builtin",
198+
"dependencies": {}
199+
},
143200
"com.unity.modules.physics": {
144201
"version": "1.0.0",
145202
"depth": 0,

Diff for: com.unity.ml-agents/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ and this project adheres to
1616
#### com.unity.ml-agents / com.unity.ml-agents.extensions (C#)
1717

1818
#### ml-agents / ml-agents-envs
19+
- Added training config feature to evenly distribute checkpoints throughout training. (#5842)
20+
- Updated training area replicator to add a condition to only replicate training areas when running a build. (#5842)
1921

2022
### Bug Fixes
2123
#### com.unity.ml-agents / com.unity.ml-agents.extensions (C#)

Diff for: com.unity.ml-agents/Runtime/Areas/TrainingAreaReplicator.cs

+19-7
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,13 @@ public class TrainingAreaReplicator : MonoBehaviour
2525
/// </summary>
2626
public float separation = 10f;
2727

28-
int3 m_GridSize = new int3(1, 1, 1);
29-
int m_areaCount = 0;
28+
/// <summary>
29+
/// Whether to replicate in the editor or in a build only. Default = true
30+
/// </summary>
31+
public bool buildOnly = true;
32+
33+
int3 m_GridSize = new(1, 1, 1);
34+
int m_AreaCount;
3035
string m_TrainingAreaName;
3136

3237
/// <summary>
@@ -57,7 +62,14 @@ public void Awake()
5762
/// </summary>
5863
public void OnEnable()
5964
{
60-
// Adds the training are replicas during OnEnable to ensure they are added before the Academy begins its work.
65+
// Adds the training as replicas during OnEnable to ensure they are added before the Academy begins its work.
66+
if (buildOnly)
67+
{
68+
#if UNITY_STANDALONE && !UNITY_EDITOR
69+
AddEnvironments();
70+
#endif
71+
return;
72+
}
6173
AddEnvironments();
6274
}
6375

@@ -95,14 +107,14 @@ void AddEnvironments()
95107
{
96108
for (int x = 0; x < m_GridSize.x; x++)
97109
{
98-
if (m_areaCount == 0)
110+
if (m_AreaCount == 0)
99111
{
100112
// Skip this first area since it already exists.
101-
m_areaCount = 1;
113+
m_AreaCount = 1;
102114
}
103-
else if (m_areaCount < numAreas)
115+
else if (m_AreaCount < numAreas)
104116
{
105-
m_areaCount++;
117+
m_AreaCount++;
106118
var area = Instantiate(baseArea, new Vector3(x * separation, y * separation, z * separation), Quaternion.identity);
107119
area.name = m_TrainingAreaName;
108120
}

Diff for: com.unity.ml-agents/Runtime/Sensors/GridSensorComponent.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ void OnDrawGizmos()
285285
var cellColors = m_DebugSensor.PerceptionBuffer;
286286
var rotation = m_GridPerception.GetGridRotation();
287287

288-
var scale = new Vector3(m_CellScale.x, 1, m_CellScale.z);
288+
var scale = new Vector3(m_CellScale.x, m_CellScale.y, m_CellScale.z);
289289
var gizmoYOffset = new Vector3(0, m_GizmoYOffset, 0);
290290
var oldGizmoMatrix = Gizmos.matrix;
291291
for (var i = 0; i < m_DebugSensor.PerceptionBuffer.Length; i++)

0 commit comments

Comments
 (0)