浏览代码

Use SemVer to check communication compatibility between C# and Python (#3760)

* [communication] Use semantic versioning to test communication compatibility between C# and Python.

- Add tests for the change.

Co-authored-by: Chris Elion <chris.elion@unity3d.com>
/develop/add-fire
GitHub 5 年前
当前提交
989cc89f
共有 8 个文件被更改,包括 188 次插入19 次删除
  1. 1
      com.unity.ml-agents/CHANGELOG.md
  2. 51
      com.unity.ml-agents/Runtime/Communicator/RpcCommunicator.cs
  3. 63
      ml-agents-envs/mlagents_envs/environment.py
  4. 31
      ml-agents-envs/mlagents_envs/tests/test_envs.py
  5. 3
      com.unity.ml-agents/Tests/Editor/Communicator.meta
  6. 55
      com.unity.ml-agents/Tests/Editor/Communicator/RpcCommunicatorTests.cs
  7. 3
      com.unity.ml-agents/Tests/Editor/Communicator/RpcCommunicatorTests.cs.meta

1
com.unity.ml-agents/CHANGELOG.md


- Added ability to start training (initialize model weights) from a previous run ID. (#3710)
- The internal event `Academy.AgentSetStatus` was renamed to `Academy.AgentPreStep` and made public.
- The offset logic was removed from DecisionRequester.
- The communication API version has been bumped up to 1.0.0 and will use [Semantic Versioning](https://semver.org/) to do compatibility checks for communication between Unity and the Python process.
### Minor Changes
- Format of console output has changed slightly and now matches the name of the model/summary directory. (#3630, #3616)

51
com.unity.ml-agents/Runtime/Communicator/RpcCommunicator.cs


#region Initialization
internal static bool CheckCommunicationVersionsAreCompatible(
string unityCommunicationVersion,
string pythonApiVersion,
string pythonLibraryVersion)
{
var unityVersion = new Version(unityCommunicationVersion);
var pythonVersion = new Version(pythonApiVersion);
if (unityVersion.Major == 0)
{
if (unityVersion.Major != pythonVersion.Major || unityVersion.Minor != pythonVersion.Minor)
{
return false;
}
}
else if (unityVersion.Major != pythonVersion.Major)
{
return false;
}
else if (unityVersion.Minor != pythonVersion.Minor)
{
// Even if we initialize, we still want to check to make sure that we inform users of minor version
// changes. This will surface any features that may not work due to minor version incompatibilities.
Debug.LogWarningFormat(
"WARNING: The communication API versions between Unity and python differ at the minor version level. " +
"Python API: {0}, Unity API: {1} Python Library Version: {2} .\n" +
"This means that some features may not work unless you upgrade the package with the lower version." +
"Please find the versions that work best together from our release page.\n" +
"https://github.com/Unity-Technologies/ml-agents/releases",
pythonApiVersion, unityCommunicationVersion, pythonLibraryVersion
);
}
return true;
}
/// <summary>
/// Sends the initialization parameters through the Communicator.
/// Is used by the academy to send initialization parameters to the communicator.

},
out input);
var pythonCommunicationVersion = initializationInput.RlInitializationInput.CommunicationVersion;
var pythonPackageVersion = initializationInput.RlInitializationInput.PackageVersion;
var unityCommunicationVersion = initParameters.unityCommunicationVersion;
var communicationIsCompatible = CheckCommunicationVersionsAreCompatible(unityCommunicationVersion,
pythonCommunicationVersion,
pythonPackageVersion);
var pythonCommunicationVersion = initializationInput.RlInitializationInput.CommunicationVersion;
var pythonPackageVersion = initializationInput.RlInitializationInput.PackageVersion;
if (pythonCommunicationVersion != initParameters.unityCommunicationVersion)
if (!communicationIsCompatible)
"Communication protocol between python ({0}) and Unity ({1}) don't match. " +
"Python library version: {2}.",
"Communication protocol between python ({0}) and Unity ({1}) have different " +
"versions which make them incompatible. Python library version: {2}.",
pythonCommunicationVersion, initParameters.unityCommunicationVersion,
pythonPackageVersion
);

63
ml-agents-envs/mlagents_envs/environment.py


import atexit
from distutils.version import StrictVersion
import glob
import uuid
import numpy as np

import signal
import struct
logger = get_logger(__name__)

# Command line argument used to pass the port to the executable environment.
PORT_COMMAND_LINE_ARG = "--mlagents-port"
@staticmethod
def _raise_version_exception(unity_com_ver: str) -> None:
raise UnityEnvironmentException(
f"The communication API version is not compatible between Unity and python. "
f"Python API: {UnityEnvironment.API_VERSION}, Unity API: {unity_com_ver}.\n "
f"Please go to https://github.com/Unity-Technologies/ml-agents/releases/tag/latest_release "
f"to download the latest version of ML-Agents."
)
@staticmethod
def check_communication_compatibility(
unity_com_ver: str, python_api_version: str, unity_package_version: str
) -> bool:
unity_communicator_version = StrictVersion(unity_com_ver)
api_version = StrictVersion(python_api_version)
if unity_communicator_version.version[0] == 0:
if (
unity_communicator_version.version[0] != api_version.version[0]
or unity_communicator_version.version[1] != api_version.version[1]
):
# Minor beta versions differ.
return False
elif unity_communicator_version.version[0] != api_version.version[0]:
# Major versions mismatch.
return False
elif unity_communicator_version.version[1] != api_version.version[1]:
# Non-beta minor versions mismatch. Log a warning but allow execution to continue.
logger.warning(
f"WARNING: The communication API versions between Unity and python differ at the minor version level. "
f"Python API: {python_api_version}, Unity API: {unity_communicator_version}.\n"
f"This means that some features may not work unless you upgrade the package with the lower version."
f"Please find the versions that work best together from our release page.\n"
"https://github.com/Unity-Technologies/ml-agents/releases"
)
else:
logger.info(
f"Connected to Unity environment with package version {unity_package_version} "
f"and communication version {unity_com_ver}"
)
return True
def __init__(
self,
file_name: Optional[str] = None,

self._close(0)
raise
unity_communicator_version = aca_params.communication_version
if unity_communicator_version != UnityEnvironment.API_VERSION:
if not UnityEnvironment.check_communication_compatibility(
aca_params.communication_version,
UnityEnvironment.API_VERSION,
aca_params.package_version,
):
raise UnityEnvironmentException(
f"The communication API version is not compatible between Unity and python. "
f"Python API: {UnityEnvironment.API_VERSION}, Unity API: {unity_communicator_version}.\n "
f"Please go to https://github.com/Unity-Technologies/ml-agents/releases/tag/latest_release "
f"to download the latest version of ML-Agents."
)
else:
logger.info(
f"Connected to Unity environment with package version {aca_params.package_version} "
f"and communication version {aca_params.communication_version}"
)
UnityEnvironment._raise_version_exception(aca_params.communication_version)
self._env_state: Dict[str, Tuple[DecisionSteps, TerminalSteps]] = {}
self._env_specs: Dict[str, BehaviorSpec] = {}
self._env_actions: Dict[str, np.ndarray] = {}

31
ml-agents-envs/mlagents_envs/tests/test_envs.py


assert comm.has_been_closed
def test_check_communication_compatibility():
unity_ver = "1.0.0"
python_ver = "1.0.0"
unity_package_version = "0.15.0"
assert UnityEnvironment.check_communication_compatibility(
unity_ver, python_ver, unity_package_version
)
unity_ver = "1.1.0"
assert UnityEnvironment.check_communication_compatibility(
unity_ver, python_ver, unity_package_version
)
unity_ver = "2.0.0"
assert not UnityEnvironment.check_communication_compatibility(
unity_ver, python_ver, unity_package_version
)
unity_ver = "0.16.0"
python_ver = "0.16.0"
assert UnityEnvironment.check_communication_compatibility(
unity_ver, python_ver, unity_package_version
)
unity_ver = "0.17.0"
assert not UnityEnvironment.check_communication_compatibility(
unity_ver, python_ver, unity_package_version
)
unity_ver = "1.16.0"
assert not UnityEnvironment.check_communication_compatibility(
unity_ver, python_ver, unity_package_version
)
def test_returncode_to_signal_name():
assert UnityEnvironment.returncode_to_signal_name(-2) == "SIGINT"
assert UnityEnvironment.returncode_to_signal_name(42) is None

3
com.unity.ml-agents/Tests/Editor/Communicator.meta


fileFormatVersion: 2
guid: da8f640243c749388a0329393c8fce64
timeCreated: 1586386315

55
com.unity.ml-agents/Tests/Editor/Communicator/RpcCommunicatorTests.cs


using System;
using System.Collections;
using System.Text.RegularExpressions;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
namespace MLAgents.Tests.Communicator
{
[TestFixture]
public class RpcCommunicatorTests
{
[Test]
public void TestCheckCommunicationVersionsAreCompatible()
{
var unityVerStr = "1.0.0";
var pythonVerStr = "1.0.0";
var pythonPackageVerStr = "0.16.0";
Assert.IsTrue(RpcCommunicator.CheckCommunicationVersionsAreCompatible(unityVerStr,
pythonVerStr,
pythonPackageVerStr));
LogAssert.NoUnexpectedReceived();
pythonVerStr = "1.1.0";
Assert.IsTrue(RpcCommunicator.CheckCommunicationVersionsAreCompatible(unityVerStr,
pythonVerStr,
pythonPackageVerStr));
// Ensure that a warning was printed.
LogAssert.Expect(LogType.Warning, new Regex("(.\\s)+"));
unityVerStr = "2.0.0";
Assert.IsFalse(RpcCommunicator.CheckCommunicationVersionsAreCompatible(unityVerStr,
pythonVerStr,
pythonPackageVerStr));
unityVerStr = "0.15.0";
pythonVerStr = "0.15.0";
Assert.IsTrue(RpcCommunicator.CheckCommunicationVersionsAreCompatible(unityVerStr,
pythonVerStr,
pythonPackageVerStr));
unityVerStr = "0.16.0";
Assert.IsFalse(RpcCommunicator.CheckCommunicationVersionsAreCompatible(unityVerStr,
pythonVerStr,
pythonPackageVerStr));
unityVerStr = "1.15.0";
Assert.IsFalse(RpcCommunicator.CheckCommunicationVersionsAreCompatible(unityVerStr,
pythonVerStr,
pythonPackageVerStr));
}
}
}

3
com.unity.ml-agents/Tests/Editor/Communicator/RpcCommunicatorTests.cs.meta


fileFormatVersion: 2
guid: 251fab8dff424abb95b2b381c7c924c3
timeCreated: 1586386329
正在加载...
取消
保存