using System.IO;
using System.IO.Abstractions;
using Google.Protobuf;
using System.Collections.Generic;
namespace MLAgents
{
///
/// Responsible for writing demonstration data to file.
///
public class DemonstrationStore
{
public const int MetaDataBytes = 32; // Number of bytes allocated to metadata in demo file.
readonly IFileSystem m_FileSystem;
const string k_DemoDirectory = "Assets/Demonstrations/";
const string k_ExtensionType = ".demo";
string m_FilePath;
DemonstrationMetaData m_MetaData;
Stream m_Writer;
float m_CumulativeReward;
WriteAdapter m_WriteAdapter = new WriteAdapter();
public DemonstrationStore(IFileSystem fileSystem)
{
if (fileSystem != null)
{
m_FileSystem = fileSystem;
}
else
{
m_FileSystem = new FileSystem();
}
}
///
/// Initializes the Demonstration Store, and writes initial data.
///
public void Initialize(
string demonstrationName, BrainParameters brainParameters, string brainName)
{
CreateDirectory();
CreateDemonstrationFile(demonstrationName);
WriteBrainParameters(brainName, brainParameters);
}
///
/// Checks for the existence of the Demonstrations directory
/// and creates it if it does not exist.
///
void CreateDirectory()
{
if (!m_FileSystem.Directory.Exists(k_DemoDirectory))
{
m_FileSystem.Directory.CreateDirectory(k_DemoDirectory);
}
}
///
/// Creates demonstration file.
///
void CreateDemonstrationFile(string demonstrationName)
{
// Creates demonstration file.
var literalName = demonstrationName;
m_FilePath = k_DemoDirectory + literalName + k_ExtensionType;
var uniqueNameCounter = 0;
while (m_FileSystem.File.Exists(m_FilePath))
{
literalName = demonstrationName + "_" + uniqueNameCounter;
m_FilePath = k_DemoDirectory + literalName + k_ExtensionType;
uniqueNameCounter++;
}
m_Writer = m_FileSystem.File.Create(m_FilePath);
m_MetaData = new DemonstrationMetaData { demonstrationName = demonstrationName };
var metaProto = m_MetaData.ToProto();
metaProto.WriteDelimitedTo(m_Writer);
}
///
/// Writes brain parameters to file.
///
void WriteBrainParameters(string brainName, BrainParameters brainParameters)
{
// Writes BrainParameters to file.
m_Writer.Seek(MetaDataBytes + 1, 0);
var brainProto = brainParameters.ToProto(brainName, false);
brainProto.WriteDelimitedTo(m_Writer);
}
///
/// Write AgentInfo experience to file.
///
public void Record(AgentInfo info, List sensors)
{
// Increment meta-data counters.
m_MetaData.numberExperiences++;
m_CumulativeReward += info.reward;
if (info.done)
{
EndEpisode();
}
// Generate observations and add AgentInfo to file.
var agentProto = info.ToInfoActionPairProto();
foreach (var sensor in sensors)
{
agentProto.AgentInfo.Observations.Add(sensor.GetObservationProto(m_WriteAdapter));
}
agentProto.WriteDelimitedTo(m_Writer);
}
///
/// Performs all clean-up necessary
///
public void Close()
{
EndEpisode();
m_MetaData.meanReward = m_CumulativeReward / m_MetaData.numberEpisodes;
WriteMetadata();
m_Writer.Close();
}
///
/// Performs necessary episode-completion steps.
///
void EndEpisode()
{
m_MetaData.numberEpisodes += 1;
}
///
/// Writes meta-data.
///
void WriteMetadata()
{
var metaProto = m_MetaData.ToProto();
var metaProtoBytes = metaProto.ToByteArray();
m_Writer.Write(metaProtoBytes, 0, metaProtoBytes.Length);
m_Writer.Seek(0, 0);
metaProto.WriteDelimitedTo(m_Writer);
}
}
}