Initial Commit
This commit is contained in:
Родитель
4e9e3aff94
Коммит
3e10ec2102
|
@ -3,7 +3,6 @@ using Unity.Collections;
|
|||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Entities;
|
||||
using Unity.Jobs;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ECS_MLAgents_v0.Core
|
||||
{
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
using System;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using System.IO.MemoryMappedFiles;
|
||||
using System.IO;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
|
||||
|
||||
namespace ECS_MLAgents_v0.Core{
|
||||
public class ExternalDecision : IAgentDecision
|
||||
{
|
||||
|
||||
// [ Unity Ready (1) , nAgents (4) , sensorSize (4) , actuatorSize (4) , Data
|
||||
|
||||
// TODO : This capacity needs to scale / communicate multiple times per step ?
|
||||
private const int FILE_CAPACITY = 200000;
|
||||
private const int NUMBER_AGENTS_POSITION = 0;
|
||||
private const int SENSOR_SIZE_POSITION = 4;
|
||||
private const int ACTUATOR_SIZE_POSITION = 8;
|
||||
private const int UNITY_READY_POSITION = 12;
|
||||
private const int SENSOR_DATA_POSITION = 13;
|
||||
|
||||
private const int PYTHON_READY_POSITION = 100000;
|
||||
private const int ACTUATOR_DATA_POSITION = 100001;
|
||||
|
||||
|
||||
private float[] actuatorData = new float[0];
|
||||
|
||||
// This is a temporary test file
|
||||
// TODO : Replace with a file creation system
|
||||
// TODO : Implement the communication in a separate class
|
||||
// TODO : Have separate files for sensor and actuators
|
||||
private string filenameWrite = "Assets/shared_communication_file.txt";
|
||||
|
||||
private MemoryMappedViewAccessor accessor;
|
||||
|
||||
public ExternalDecision()
|
||||
{
|
||||
var mmf = MemoryMappedFile.CreateFromFile(filenameWrite, FileMode.Open, "Test");
|
||||
accessor = mmf.CreateViewAccessor(
|
||||
0, FILE_CAPACITY, MemoryMappedFileAccess.ReadWrite);
|
||||
// accessor.WriteArray(0, new bool[FILE_CAPACITY], 0, FILE_CAPACITY);
|
||||
accessor.Write(PYTHON_READY_POSITION, false);
|
||||
accessor.Write(UNITY_READY_POSITION, false);
|
||||
Debug.Log("Is Ready to Communicate");
|
||||
}
|
||||
|
||||
public JobHandle DecideBatch(
|
||||
ref NativeArray<float> sensor,
|
||||
ref NativeArray<float> actuator,
|
||||
int sensorSize,
|
||||
int actuatorSize,
|
||||
int nAgents,
|
||||
JobHandle handle)
|
||||
{
|
||||
Profiler.BeginSample("Communicating");
|
||||
if (sensor.Length > 4 * 50000)
|
||||
{
|
||||
throw new Exception("TOO much data to send");
|
||||
}
|
||||
|
||||
if (actuator.Length > 4 * 50000)
|
||||
{
|
||||
throw new Exception("TOO much data to send");
|
||||
}
|
||||
|
||||
if (actuatorData.Length < actuator.Length)
|
||||
{
|
||||
actuatorData = new float[actuator.Length];
|
||||
}
|
||||
|
||||
|
||||
accessor.Write(NUMBER_AGENTS_POSITION, nAgents);
|
||||
accessor.Write(SENSOR_SIZE_POSITION, sensorSize);
|
||||
accessor.Write(ACTUATOR_SIZE_POSITION, actuatorSize);
|
||||
|
||||
accessor.WriteArray(SENSOR_DATA_POSITION, sensor.ToArray(), 0, sensor.Length);
|
||||
|
||||
accessor.Write(PYTHON_READY_POSITION, false);
|
||||
|
||||
accessor.Write(UNITY_READY_POSITION, true);
|
||||
|
||||
|
||||
var readyToContinue = false;
|
||||
int loopIter = 0;
|
||||
while (!readyToContinue)
|
||||
{
|
||||
loopIter++;
|
||||
readyToContinue = accessor.ReadBoolean(PYTHON_READY_POSITION);
|
||||
readyToContinue = readyToContinue || loopIter > 200000;
|
||||
if (loopIter > 200000)
|
||||
{
|
||||
Debug.Log("Missed Communication");
|
||||
}
|
||||
}
|
||||
|
||||
accessor.ReadArray(ACTUATOR_DATA_POSITION, actuatorData, 0, actuator.Length);
|
||||
actuator.CopyFrom(actuatorData);
|
||||
|
||||
Profiler.BeginSample("Communicating");
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 03d6cba5b00b14245aee6796e797ffc1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -37,7 +37,7 @@ namespace ECS_MLAgents_v0.Example.SpaceWars.Scripts
|
|||
|
||||
void Start()
|
||||
{
|
||||
Time.captureFramerate = 60;
|
||||
// Time.captureFramerate = 60;
|
||||
manager = World.Active.GetOrCreateManager<EntityManager>();
|
||||
|
||||
_sensorSystem = World.Active.GetOrCreateManager<SensorPopulate>();
|
||||
|
@ -45,7 +45,8 @@ namespace ECS_MLAgents_v0.Example.SpaceWars.Scripts
|
|||
_impactSystem.Radius = 20;
|
||||
|
||||
_shipSystemA = World.Active.GetExistingManager<SmartShipSystem>();
|
||||
_shipSystemA.Decision = new NNDecision(model);
|
||||
// _shipSystemA.Decision = new NNDecision(model);
|
||||
_shipSystemA.Decision = new ExternalDecision();
|
||||
_playerSystem = World.Active.GetExistingManager<PlayerShipSystem>();
|
||||
_playerSystem.Decision = new HumanDecision();
|
||||
_playerSystem.SetNewComponentGroup(typeof(PlayerFlag));
|
||||
|
@ -60,6 +61,8 @@ namespace ECS_MLAgents_v0.Example.SpaceWars.Scripts
|
|||
ReloadTime = 1f,
|
||||
MaxReloadTime = 1f
|
||||
});
|
||||
|
||||
Spawn(100);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
import mmap
|
||||
import struct
|
||||
import numpy as np
|
||||
import time
|
||||
|
||||
class UnityCommunication:
|
||||
FILE_CAPACITY = 200000
|
||||
NUMBER_AGENTS_POSITION = 0
|
||||
SENSOR_SIZE_POSITION = 4
|
||||
ACTUATOR_SIZE_POSITION = 8
|
||||
UNITY_READY_POSITION = 12
|
||||
SENSOR_DATA_POSITION = 13
|
||||
|
||||
PYTHON_READY_POSITION = 100000
|
||||
ACTUATOR_DATA_POSITION = 100001
|
||||
|
||||
FILE_NAME = "shared_communication_file.txt"
|
||||
|
||||
def __init__(self):
|
||||
with open(self.FILE_NAME, "r+b") as f:
|
||||
# memory-map the file, size 0 means whole file
|
||||
self.accessor = mmap.mmap(f.fileno(), 0)
|
||||
|
||||
def get_int(self, position : int) -> int:
|
||||
return struct.unpack("i", self.accessor[position:position + 4])[0]
|
||||
|
||||
def read_sensor(self) -> np.ndarray:
|
||||
sensor_size = self.get_int(self.SENSOR_SIZE_POSITION)
|
||||
number_agents = self.get_int(self.NUMBER_AGENTS_POSITION)
|
||||
|
||||
sensor = np.frombuffer(
|
||||
buffer=self.accessor[self.SENSOR_DATA_POSITION: self.SENSOR_DATA_POSITION + 4*sensor_size*number_agents],
|
||||
dtype=np.float32,
|
||||
count=sensor_size * number_agents,
|
||||
offset=0
|
||||
)
|
||||
return np.reshape(sensor, (number_agents, sensor_size))
|
||||
|
||||
def get_parameters(self) -> (int, int, int):
|
||||
return self.get_int(self.NUMBER_AGENTS_POSITION), \
|
||||
self.get_int(self.SENSOR_SIZE_POSITION), \
|
||||
self.get_int(self.ACTUATOR_SIZE_POSITION)
|
||||
|
||||
def write_actuator(self, actuator: np.ndarray):
|
||||
actuator_size = self.get_int(self.ACTUATOR_SIZE_POSITION)
|
||||
number_agents = self.get_int(self.NUMBER_AGENTS_POSITION)
|
||||
|
||||
# TODO : Support more types ?
|
||||
if actuator.dtype != np.float32:
|
||||
actuator = actuator.astype(np.float32)
|
||||
|
||||
assert(actuator.shape == (number_agents, actuator_size))
|
||||
|
||||
self.accessor[self.ACTUATOR_DATA_POSITION: self.ACTUATOR_DATA_POSITION + 4*actuator_size*number_agents] = \
|
||||
actuator.tobytes()
|
||||
|
||||
def set_ready(self, flag : bool):
|
||||
self.accessor[self.PYTHON_READY_POSITION: self.PYTHON_READY_POSITION+1] = bytearray(struct.pack("b", flag))
|
||||
|
||||
def unity_ready(self) -> bool:
|
||||
return self.accessor[self.UNITY_READY_POSITION]
|
||||
|
||||
def close(self):
|
||||
self.accessor.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
comm = UnityCommunication()
|
||||
|
||||
steps = 0
|
||||
while True:
|
||||
|
||||
u_ready = False
|
||||
while not u_ready:
|
||||
u_ready = comm.unity_ready()
|
||||
steps += 1
|
||||
s = comm.read_sensor()
|
||||
nag, nse, nac = comm.get_parameters()
|
||||
time.sleep(0.1)
|
||||
comm.write_actuator(
|
||||
np.random.normal(size=(nag, nac))
|
||||
)
|
||||
comm.set_ready(True)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2f0ad029c108747edacf337bce7c2b95
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Двоичный файл не отображается.
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f0ca7a0f2c172427f92e5a877c40c2f9
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Загрузка…
Ссылка в новой задаче