This commit is contained in:
vincentpierre 2019-03-01 11:58:53 -08:00
Родитель 4e9e3aff94
Коммит 3e10ec2102
8 изменённых файлов: 228 добавлений и 3 удалений

Просмотреть файл

@ -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:

Двоичные данные
Assets/shared_communication_file.txt Executable file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: f0ca7a0f2c172427f92e5a877c40c2f9
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: