MyCaffe  1.12.2.41
Deep learning software for Windows C# programmers.
AtariGym.cs
1using AleControlLib;
2using MyCaffe.basecode;
4using System;
5using System.Collections.Generic;
6using System.Diagnostics;
7using System.Drawing;
8using System.Drawing.Drawing2D;
9using System.Drawing.Imaging;
10using System.IO;
11using System.Linq;
12using System.Runtime.InteropServices;
13using System.Text;
14using System.Threading;
15using System.Threading.Tasks;
16
17namespace MyCaffe.gym
18{
41 public class AtariGym : IXMyCaffeGym, IDisposable
42 {
43 string m_strName = "ATARI";
44 IALE m_ale = null;
45 AtariState m_state = new AtariState();
46 Log m_log;
47 ACTION[] m_rgActionsRaw;
48 List<int> m_rgFrameSkip = new List<int>();
49 CryptoRandom m_random;
50 Dictionary<string, int> m_rgActions = new Dictionary<string, int>();
51 List<KeyValuePair<string, int>> m_rgActionSet;
52 DATA_TYPE m_dt = DATA_TYPE.BLOB;
53 COLORTYPE m_ct = COLORTYPE.CT_COLOR;
54 bool m_bPreprocess = true;
55 bool m_bForceGray = false;
56 DirectBitmap m_bmpRaw = null;
57 DirectBitmap m_bmpActionRaw = null;
58 bool m_bEnableNumSkip = true;
59 int m_nFrameSkip = -1;
60
64 public AtariGym()
65 {
66 }
67
71 public void Dispose()
72 {
73 if (m_ale != null)
74 {
75 m_ale.Shutdown();
76 m_ale = null;
77 }
78
79 if (m_bmpRaw != null)
80 {
81 m_bmpRaw.Dispose();
82 m_bmpRaw = null;
83 }
84
85 if (m_bmpActionRaw != null)
86 {
87 m_bmpActionRaw.Dispose();
88 m_bmpActionRaw = null;
89 }
90 }
91
101 public void Initialize(Log log, PropertySet properties)
102 {
103 m_log = log;
104
105 if (m_ale != null)
106 {
107 m_ale.Shutdown();
108 m_ale = null;
109 }
110
111 m_ale = new ALE();
112 m_ale.Initialize();
113 m_ale.EnableDisplayScreen = false;
114 m_ale.EnableSound = false;
115 m_ale.EnableColorData = properties.GetPropertyAsBool("EnableColor", false);
116 m_ale.EnableRestrictedActionSet = true;
117 m_ale.EnableColorAveraging = true;
118 m_ale.AllowNegativeRewards = properties.GetPropertyAsBool("AllowNegativeRewards", false);
119 m_ale.EnableTerminateOnRallyEnd = properties.GetPropertyAsBool("TerminateOnRallyEnd", false);
120 m_ale.RandomSeed = (int)DateTime.Now.Ticks;
121 m_ale.RepeatActionProbability = 0.0f; // disable action repeatability
122
123 if (properties == null)
124 throw new Exception("The properties must be specified with the 'GameROM' set the the Game ROM file path.");
125
126 string strROM = properties.GetProperty("GameROM");
127 if (strROM.Contains('~'))
128 strROM = Utility.Replace(strROM, '~', ' ');
129 else
130 strROM = Utility.Replace(strROM, "[sp]", ' ');
131
132 if (!File.Exists(strROM))
133 throw new Exception("Could not find the game ROM file specified '" + strROM + "'!");
134
135 if (properties.GetPropertyAsBool("UseGrayscale", false))
136 m_ct = COLORTYPE.CT_GRAYSCALE;
137
138 m_bPreprocess = properties.GetPropertyAsBool("Preprocess", true);
139 m_bForceGray = properties.GetPropertyAsBool("ActionForceGray", false);
140 m_bEnableNumSkip = properties.GetPropertyAsBool("EnableNumSkip", true);
141 m_nFrameSkip = properties.GetPropertyAsInt("FrameSkip", -1);
142
143 m_ale.Load(strROM);
144 m_rgActionsRaw = m_ale.ActionSpace;
145 m_random = new CryptoRandom();
146 m_rgFrameSkip = new List<int>();
147
148 if (m_nFrameSkip < 0)
149 {
150 for (int i = 2; i < 5; i++)
151 {
152 m_rgFrameSkip.Add(i);
153 }
154 }
155 else
156 {
157 m_rgFrameSkip.Add(m_nFrameSkip);
158 }
159
160 m_rgActions.Add(ACTION.ACT_PLAYER_A_LEFT.ToString(), (int)ACTION.ACT_PLAYER_A_LEFT);
161 m_rgActions.Add(ACTION.ACT_PLAYER_A_RIGHT.ToString(), (int)ACTION.ACT_PLAYER_A_RIGHT);
162
163 if (!properties.GetPropertyAsBool("EnableBinaryActions", false))
164 m_rgActions.Add(ACTION.ACT_PLAYER_A_FIRE.ToString(), (int)ACTION.ACT_PLAYER_A_FIRE);
165
166 m_rgActionSet = m_rgActions.ToList();
167
168 Reset(false);
169 }
170
176 public IXMyCaffeGym Clone(PropertySet properties = null)
177 {
178 AtariGym gym = new AtariGym();
179
180 if (properties != null)
181 gym.Initialize(m_log, properties);
182
183 return gym;
184 }
185
190 {
191 get { return true; }
192 }
193
198 {
199 get { return m_dt; }
200 }
201
206 {
207 get { return new DATA_TYPE[] { DATA_TYPE.BLOB }; }
208 }
209
213 public string Name
214 {
215 get { return m_strName; }
216 }
217
221 public int UiDelay
222 {
223 get { return 0; }
224 }
225
229 public double TestingPercent
230 {
231 get { return -1; }
232 }
233
238 public Dictionary<string, int> GetActionSpace()
239 {
240 return m_rgActions;
241 }
242
246 public void Close()
247 {
248 if (m_ale != null)
249 {
250 m_ale.Shutdown();
251 m_ale = null;
252 }
253 }
254
263 public Tuple<Bitmap, SimpleDatum> Render(bool bShowUi, int nWidth, int nHeight, bool bGetAction)
264 {
265 List<double> rgData = new List<double>();
266 return Render(bShowUi, nWidth, nHeight, rgData.ToArray(), bGetAction);
267 }
268
278 public Tuple<Bitmap, SimpleDatum> Render(bool bShowUi, int nWidth, int nHeight, double[] rgData, bool bGetAction)
279 {
280 float fWid;
281 float fHt;
282
283 m_ale.GetScreenDimensions(out fWid, out fHt);
284 byte[] rgRawData = m_ale.GetScreenData(m_ct);
285
286 Tuple<DirectBitmap, SimpleDatum> data = getData(m_ct, (int)fWid, (int)fHt, 35, 2, rgRawData, m_bPreprocess, bGetAction, m_bForceGray);
287 Bitmap bmp = null;
288
289 if (bShowUi)
290 {
291 if (data.Item1.Bitmap.Width != nWidth || data.Item1.Bitmap.Height != nHeight)
292 bmp = ImageTools.ResizeImage(data.Item1.Bitmap, nWidth, nHeight);
293 else
294 bmp = new Bitmap(data.Item1.Bitmap);
295 }
296
297 return new Tuple<Bitmap, SimpleDatum>(bmp, data.Item2);
298 }
299
300 private Tuple<DirectBitmap, SimpleDatum> getData(COLORTYPE ct, int nWid, int nHt, int nOffset, int nDownsample, byte[] rg, bool bPreprocess, bool bGetAction, bool bForceGray)
301 {
302 int nChannels = (bPreprocess || bForceGray) ? 1 : 3;
303 int nSize = Math.Min(nWid, nHt);
304 int nDsSize = nSize / nDownsample;
305 int nX = 0;
306 int nY = 0;
307 bool bY = false;
308 bool bX = false;
309
310 if (m_bmpRaw != null && (m_bmpRaw.Width != nWid || m_bmpRaw.Height != nHt))
311 {
312 m_bmpRaw.Dispose();
313 m_bmpRaw = null;
314 }
315
316 if (m_bmpActionRaw != null && (m_bmpActionRaw.Width != nDsSize || m_bmpActionRaw.Height != nDsSize))
317 {
318 m_bmpActionRaw.Dispose();
319 m_bmpActionRaw = null;
320 }
321
322 if (m_bmpRaw == null)
323 m_bmpRaw = new DirectBitmap(nWid, nHt);
324
325 if (m_bmpActionRaw == null)
326 m_bmpActionRaw = new DirectBitmap(nDsSize, nDsSize);
327
328 DirectBitmap bmp = m_bmpRaw;
329 Valuemap dataV = null;
330 Bytemap dataB = null;
331
332 if (bGetAction)
333 {
334 if (m_bPreprocess)
335 dataV = new Valuemap(nChannels, nDsSize, nDsSize);
336 else
337 dataB = new Bytemap(nChannels, nDsSize, nDsSize);
338 }
339
340 for (int y = 0; y < nHt; y++)
341 {
342 if (y % nDownsample == 0 && y > nOffset && y < nOffset + nSize)
343 bY = true;
344 else
345 bY = false;
346
347 for (int x = 0; x < nWid; x++)
348 {
349 int nIdx = (y * nWid) + x;
350 int nR = rg[nIdx];
351 int nG = nR;
352 int nB = nR;
353
354 if (x % nDownsample == 0)
355 bX = true;
356 else
357 bX = false;
358
359 if (ct == COLORTYPE.CT_COLOR)
360 {
361 nG = rg[nIdx + (nWid * nHt * 1)];
362 nB = rg[nIdx + (nWid * nHt * 2)];
363 }
364
365 Color clr = Color.FromArgb(nR, nG, nB);
366
367 bmp.SetPixel(x, y, clr);
368
369 if (bForceGray)
370 {
371 int nClr = (nR + nG + nB) / 3;
372 clr = Color.FromArgb(nClr, nClr, nClr);
373 }
374
375 if (bY && bX && (dataB != null || dataV != null))
376 {
377 if (bPreprocess)
378 {
379 if (nR != 144 && nR != 109 && nR != 0)
380 dataV.SetPixel(nX, nY, 1.0);
381 }
382 else
383 {
384 dataB.SetPixel(nX, nY, clr);
385 }
386
387 nX++;
388 }
389 }
390
391 if (bY)
392 {
393 nX = 0;
394 nY++;
395 }
396 }
397
398 SimpleDatum sd = null;
399
400 if (m_bPreprocess)
401 {
402 if (dataV != null)
403 sd = new SimpleDatum(dataV);
404 }
405 else
406 {
407 if (dataB != null)
408 sd = new SimpleDatum(dataB);
409 }
410
411 return new Tuple<DirectBitmap, SimpleDatum>(bmp, sd);
412 }
413
420 public Tuple<State, double, bool> Reset(bool bGetLabel, PropertySet props = null)
421 {
422 m_state = new AtariState();
423 m_ale.ResetGame();
424 return new Tuple<State, double, bool>(m_state.Clone(), 1, m_ale.GameOver);
425 }
426
434 public Tuple<State, double, bool> Step(int nAction, bool bGetLabel, PropertySet propExtra = null)
435 {
436 ACTION action = (ACTION)m_rgActionSet[nAction].Value;
437 double dfReward = m_ale.Act(action);
438
439 if (m_bEnableNumSkip)
440 {
441 int nIdx = 0;
442
443 if (m_rgFrameSkip.Count > 1)
444 nIdx = m_random.Next(m_rgFrameSkip.Count);
445
446 int nNumSkip = m_rgFrameSkip[nIdx];
447
448 for (int i = 0; i < nNumSkip; i++)
449 {
450 dfReward += m_ale.Act(action);
451 }
452 }
453
454 return new Tuple<State, double, bool>(new AtariState(), dfReward, m_ale.GameOver);
455 }
456
464 {
465 if (dt == DATA_TYPE.DEFAULT)
466 dt = DATA_TYPE.BLOB;
467
468 if (dt != DATA_TYPE.BLOB)
469 {
470 if (log == null)
471 log = m_log;
472
473 if (log != null)
474 log.WriteLine("WARNING: This gym only supports the BLOB type, the datatype will be changed to BLOB.");
475 else
476 throw new Exception("This gym only supports the BLOB type.");
477
478 dt = DATA_TYPE.BLOB;
479 }
480
481 int nH = 80;
482 int nW = 80;
483 int nC = 1;
484
485 SourceDescriptor srcTrain = new SourceDescriptor((int)GYM_DS_ID.ATARI, Name + ".training", nW, nH, nC, false, false);
486 SourceDescriptor srcTest = new SourceDescriptor((int)GYM_SRC_TEST_ID.ATARI, Name + ".testing", nW, nH, nC, false, false);
487 DatasetDescriptor ds = new DatasetDescriptor((int)GYM_SRC_TRAIN_ID.ATARI, Name, null, null, srcTrain, srcTest, "AtariGym", "Atari Gym", null, GYM_TYPE.DYNAMIC);
488
489 m_dt = dt;
490
491 return ds;
492 }
493 }
494
495 class AtariState : State
496 {
497 public AtariState()
498 {
499 }
500
501 public AtariState(AtariState s)
502 {
503 }
504
505 public override State Clone()
506 {
507 return new AtariState(this);
508 }
509
510 public override SimpleDatum GetData(bool bNormalize, out int nDataLen)
511 {
512 nDataLen = 0;
513 return new SimpleDatum();
514 }
515 }
516}
The Bytemap operates similar to a bitmap but is actually just an array of bytes.
Definition: Bytemap.cs:15
void SetPixel(int nX, int nY, byte clr)
Set a given pixel to a given color.
Definition: Bytemap.cs:65
The CryptoRandom is a random number generator that can use either the standard .Net Random objec or t...
Definition: CryptoRandom.cs:14
int Next(int nMinVal, int nMaxVal, bool bMaxInclusive=true)
Returns a random int within the range
The DirectBitmap class provides an efficient bitmap creating class.
Definition: DirectBitmap.cs:19
int Height
Returns the bitmap height.
Definition: DirectBitmap.cs:35
void Dispose()
Release all resources used.
void SetPixel(int x, int y, Color colour)
Sets a pixel within the bitmap with the specified color.
Definition: DirectBitmap.cs:65
int Width
Returns the bitmap width.
Definition: DirectBitmap.cs:39
The ImageTools class is a helper class used to manipulate image data.
Definition: ImageTools.cs:16
static Bitmap ResizeImage(Image image, int width, int height)
Resize the image to the specified width and height.
Definition: ImageTools.cs:39
The Log class provides general output in text form.
Definition: Log.cs:13
void WriteLine(string str, bool bOverrideEnabled=false, bool bHeader=false, bool bError=false, bool bDisable=false)
Write a line of output.
Definition: Log.cs:80
Specifies a key-value pair of properties.
Definition: PropertySet.cs:16
string GetProperty(string strName, bool bThrowExceptions=true)
Returns a property as a string value.
Definition: PropertySet.cs:146
int GetPropertyAsInt(string strName, int nDefault=0)
Returns a property as an integer value.
Definition: PropertySet.cs:287
bool GetPropertyAsBool(string strName, bool bDefault=false)
Returns a property as a boolean value.
Definition: PropertySet.cs:267
The SimpleDatum class holds a data input within host memory.
Definition: SimpleDatum.cs:161
The Utility class provides general utility funtions.
Definition: Utility.cs:35
static string Replace(string str, char ch1, char ch2)
Replaces each instance of one character with another character in a given string.
Definition: Utility.cs:864
The Realmap operates similar to a bitmap but is actually just an array of doubles.
Definition: Valuemap.cs:15
void SetPixel(int nX, int nY, double clr)
Set a given pixel to a given color.
Definition: Valuemap.cs:65
The DatasetDescriptor class describes a dataset which contains both a training data source and testin...
The SourceDescriptor class contains all information describing a data source.
The Atari Gym provides acess to the Atari-2600 Emulator from Stella (https://github....
Definition: AtariGym.cs:42
string Name
Returns the gym's name.
Definition: AtariGym.cs:214
int UiDelay
Returns the delay to use (if any) when the user-display is visible.
Definition: AtariGym.cs:222
Tuple< State, double, bool > Step(int nAction, bool bGetLabel, PropertySet propExtra=null)
Step the gym one step in its simulation.
Definition: AtariGym.cs:434
Tuple< Bitmap, SimpleDatum > Render(bool bShowUi, int nWidth, int nHeight, bool bGetAction)
Render the gym's current state on a bitmap and SimpleDatum.
Definition: AtariGym.cs:263
DATA_TYPE SelectedDataType
Returns the selected data type.
Definition: AtariGym.cs:198
DatasetDescriptor GetDataset(DATA_TYPE dt, Log log=null)
Returns the dataset descriptor of the dynamic dataset produced by the Gym.
Definition: AtariGym.cs:463
void Initialize(Log log, PropertySet properties)
Initialize the gym with the specified properties.
Definition: AtariGym.cs:101
AtariGym()
The constructor.
Definition: AtariGym.cs:64
double TestingPercent
Returns the testinng percent of -1, which then uses the default of 0.2.
Definition: AtariGym.cs:230
DATA_TYPE[] SupportedDataType
Returns the data types supported by this gym.
Definition: AtariGym.cs:206
bool RequiresDisplayImage
Returns true indicating that this Gym requires a display image.
Definition: AtariGym.cs:190
void Dispose()
Release all resources used.
Definition: AtariGym.cs:71
Tuple< State, double, bool > Reset(bool bGetLabel, PropertySet props=null)
Reset the state of the gym.
Definition: AtariGym.cs:420
void Close()
Shutdown and close the gym.
Definition: AtariGym.cs:246
IXMyCaffeGym Clone(PropertySet properties=null)
Create a new copy of the gym.
Definition: AtariGym.cs:176
Dictionary< string, int > GetActionSpace()
Returns the action space as a dictionary of name,actionid pairs.
Definition: AtariGym.cs:238
Tuple< Bitmap, SimpleDatum > Render(bool bShowUi, int nWidth, int nHeight, double[] rgData, bool bGetAction)
Render the gyms specified data.
Definition: AtariGym.cs:278
State()
The constructor.
Definition: Interfaces.cs:346
The IXMyCaffeGym interface is used to interact with each Gym.
Definition: Interfaces.cs:99
The descriptors namespace contains all descriptor used to describe various items stored within the da...
The MyCaffe.basecode contains all generic types used throughout MyCaffe.
Definition: Annotation.cs:12
GYM_TYPE
Defines the gym type (if any).
Definition: Interfaces.cs:116
DATA_TYPE
Defines the gym data type.
Definition: Interfaces.cs:135
The MyCaffe.gym namespace contains all classes related to the Gym's supported by MyCaffe.
GYM_SRC_TRAIN_ID
Defines the Standard GYM Training Data Source ID's.
Definition: Interfaces.cs:45
GYM_DS_ID
Defines the Standard GYM Dataset ID's.
Definition: Interfaces.cs:18
GYM_SRC_TEST_ID
Defines the Standard GYM Testing Data Source ID's.
Definition: Interfaces.cs:72
The MyCaffe namespace contains the main body of MyCaffe code that closesly tracks the C++ Caffe open-...
Definition: Annotation.cs:12