Main Content

ステップ関数とリセット関数を使用したカスタム環境の作成

この例では、独自の MATLAB® 関数 stepreset を作成してカスタム環境を作成する方法を示します。

関数rlFunctionEnvを使用すると、観測仕様、アクション仕様、および提供する関数 step と関数 reset から MATLAB 強化学習環境を作成できます。その後、この環境で強化学習エージェントに学習させることができます。この例では、必要な関数 step と関数 reset は既に定義されています。

多くの補助関数を必要とせず、特別な可視化要件がない単純な環境では、カスタム関数を使用した環境を作成することが特に役立ちます。より複雑な環境の場合は、テンプレート クラスを使用して環境オブジェクトを作成できます。詳細については、Create Custom Environment from Class Templateを参照してください。

強化学習環境の作成の詳細については、Reinforcement Learning EnvironmentsおよびCreate Custom Simulink Environmentsを参照してください。

離散行動空間カートポール MATLAB 環境

カートポール環境は、摩擦のないトラックに沿って移動するカート上の非駆動ジョイントに取り付けられたポールです。学習の目標は、振子が倒れず直立した状態を維持することです。

この環境では、次のようにします。

  • 振子が倒立平衡状態となっている位置を 0 ラジアンとし、鉛直下向きとなっている位置を π ラジアンとする。

  • 振子は、-0.05 ラジアンから 0.05 ラジアンまでの初期角度で直立して開始する。

  • エージェントから環境への力のアクション信号は、-10 N または 10 N とする。

  • 環境からの観測値は、カートの位置、カートの速度、振子の角度、および振子の角速度とする。

  • ポールが垂直から 12 度を超えるか、カートが元の位置から 2.4 m を超えて移動した場合、エピソードの終了とする。

  • ポールが直立を保っているすべてのタイム ステップに対し、+1 の報酬が提供される。振子が落下すると、-10 のペナルティが適用される。

このモデルの詳細については、Load Predefined Control System Environmentsを参照してください。

観測仕様とアクション仕様

環境からの観測値は、カートの位置、カートの速度、振子の角度、および振子の角度の微分です。

ObsInfo = rlNumericSpec([4 1]);
ObsInfo.Name = "CartPole States";
ObsInfo.Description = 'x, dx, theta, dtheta';

この環境は、エージェントが 2 つの有効な力の値 (-10 または 10 N) のいずれかをカートに適用できる離散行動空間をもちます。

ActInfo = rlFiniteSetSpec([-10 10]);
ActInfo.Name = "CartPole Action";

環境アクションと観測値の指定の詳細については、rlNumericSpecおよびrlFiniteSetSpecを参照してください。

環境のリセット関数とステップ関数の定義

カスタム環境を定義するには、まずカスタム関数 stepreset を指定します。これらの関数は、現在の作業フォルダーまたは MATLAB パス上になければなりません。

関数 reset は、環境の初期状態を設定します。この関数は次のシグネチャをもたなければなりません。

[InitialObservation,Info] = myResetFunction()

最初の出力引数は初期観測値です。2 番目の出力引数には、あるステップから次のステップに渡す任意の有用な環境情報 (環境の状態、状態やパラメーターを格納する構造体など) を指定できます。

学習 (またはシミュレーション) エピソードの開始時に、train (または sim) はリセット関数を呼び出し、2 番目の出力引数を使用してカスタム環境の Info プロパティを初期化します。学習 (またはシミュレーション) ステップにおいて、train (または sim) は、Info の現在の値を StepFcn の 2 番目の入力引数として指定し、StepFcn によって返された 4 番目の出力引数を使用して Info の値を更新します。

この例では、2 番目の引数を使用して、カートポール環境の初期状態 (カートの位置と速度、振子の角度、振子の角度の微分) を保存します。関数 reset は、環境がリセットされるたびにカートの角度をランダムな値に設定します。

この例では、myResetFunction.m で定義されたカスタム リセット関数を使用します。

type myResetFunction.m
function [InitialObservation, InitialState] = myResetFunction()
% Reset function to place custom cart-pole environment into a random
% initial state.

% Theta (randomize)
T0 = 2 * 0.05 * rand() - 0.05;
% Thetadot
Td0 = 0;
% X
X0 = 0;
% Xdot
Xd0 = 0;

% Return initial environment state variables as logged signals.
InitialState = [X0;Xd0;T0;Td0];
InitialObservation = InitialState;

end

関数 step は、あるアクションに基づいて、環境が次の状態にどのように進むかを指定します。この関数は次のシグネチャをもたなければなりません。

[NextObservation,Reward,IsDone,UpdatedInfo] = myStepFunction(Action,Info)

新しい状態を計算するために、ステップ関数は Info に保存されている現在の状態に動的方程式を適用します。その後、関数は更新された状態を UpdatedInfo に返します。次の学習 (またはシミュレーション) ステップで、train または sim は、前のステップで取得した 4 番目の出力引数 UpdatedInfo を受け取り、それを 2 番目の入力引数 Info としてステップ関数に提供します。

この例では、myStepFunction.m で定義されたカスタム ステップ関数を使用します。実装を簡単にするために、この関数は step が実行されるたびにカートの質量などの物理定数を再定義します。別の方法は、リセット関数で物理定数を定義し、状態とパラメーターの両方を格納する構造体として Info を定義し、Info を使用して物理定数と環境状態を保存することです。この代替実装を使用すると、必要に応じて、シミュレーション時や学習時に一部のパラメーターを簡単に変更することができます。

type myStepFunction.m
function [NextObs,Reward,IsDone,NextState] = myStepFunction(Action,State)
% Custom step function to construct cart-pole environment for the function
% name case.
%
% This function applies the given action to the environment and evaluates
% the system dynamics for one simulation step.

% Define the environment constants.

% Acceleration due to gravity in m/s^2
Gravity = 9.8;
% Mass of the cart
CartMass = 1.0;
% Mass of the pole
PoleMass = 0.1;
% Half the length of the pole
HalfPoleLength = 0.5;
% Max force the input can apply
MaxForce = 10;
% Sample time
Ts = 0.02;
% Pole angle at which to fail the episode
AngleThreshold = 12 * pi/180;
% Cart distance at which to fail the episode
DisplacementThreshold = 2.4;
% Reward each time step the cart-pole is balanced
RewardForNotFalling = 1;
% Penalty when the cart-pole fails to balance
PenaltyForFalling = -10;

% Check if the given action is valid.
if ~ismember(Action,[-MaxForce MaxForce])
    error('Action must be %g for going left and %g for going right.',...
        -MaxForce,MaxForce);
end
Force = Action;

% Unpack the state vector from the logged signals.
XDot = State(2);
Theta = State(3);
ThetaDot = State(4);

% Cache to avoid recomputation.
CosTheta = cos(Theta);
SinTheta = sin(Theta);
SystemMass = CartMass + PoleMass;
temp = (Force + PoleMass*HalfPoleLength*ThetaDot*ThetaDot*SinTheta)/SystemMass;

% Apply motion equations.
ThetaDotDot = (Gravity*SinTheta - CosTheta*temp) / ...
    (HalfPoleLength*(4.0/3.0 - PoleMass*CosTheta*CosTheta/SystemMass));
XDotDot  = temp - PoleMass*HalfPoleLength*ThetaDotDot*CosTheta/SystemMass;

% Perform Euler integration to calculate next state.
NextState = State + Ts.*[XDot;XDotDot;ThetaDot;ThetaDotDot];

% Copy next state to next observation.
NextObs = NextState;

% Check terminal condition.
X = NextObs(1);
Theta = NextObs(3);
IsDone = abs(X) > DisplacementThreshold || abs(Theta) > AngleThreshold;

% Calculate reward.
if ~IsDone
    Reward = RewardForNotFalling;
else
    Reward = PenaltyForFalling;
end

end

rlFunctionEnvを使用して、観測仕様とアクション仕様、および関数 step と関数 reset の名前を使用してカスタム環境オブジェクトを作成します。

env = rlFunctionEnv(ObsInfo,ActInfo,"myStepFunction","myResetFunction");

環境の動作を確認するために、rlFunctionEnv は環境の作成後に自動的にvalidateEnvironmentを呼び出します。

無名関数を使用して追加の引数を渡す

rlFunctionEnv に渡さなければならないカスタム リセット関数とカスタム ステップ関数には、それぞれ 0 個と 2 個の引数が必要ですが、無名関数を使用することでこの制限を回避できます。具体的には、rlFunctionEnv に渡される関数 reset と関数 step を無名関数 (それぞれ 0 個と 2 個の引数) として定義します。これらの無名関数は次に、追加の引数をもつカスタム関数を呼び出します。

たとえば、追加の引数 arg1arg2 を関数 step と関数 reset の両方に渡すには、次の関数を記述できます。

[InitialObservation,Info] = myResetFunction(arg1,arg2)
[Observation,Reward,IsDone,Info] = myStepFunction(Action,Info,arg1,arg2)

次に、MATLAB ワークスペースの arg1arg2 を使用して、それぞれ 0 個と 2 個の引数をもつ無名関数 reset と無名関数 step に対し、以下のハンドルを定義します。

ResetHandle = @() myResetFunction(arg1,arg2);
StepHandle = @(Action,Info) myStepFunction(Action,Info,arg1,arg2);

ResetHandleStepHandle の作成時に arg1arg2 が使用可能な場合、両方の無名関数のワークスペースにそれらの値が含められます。MATLAB ワークスペースから変数をクリアした場合でも、値は関数のワークスペース内に保持されます。ResetHandleStepHandle が評価されると、myResetFunctionmyStepFunction が呼び出され、arg1arg2 のコピーが渡されます。詳細については、無名関数を参照してください。

追加の入力引数を使用すると、より効率的な環境実装を作成できます。たとえば、myStepFunction2.m は、環境定数を 3 番目の入力引数 (envPars) として受け取るカスタム ステップ関数です。そうすることで、この関数は各ステップで環境定数が再定義されることを回避します。

type myStepFunction2.m
function [NextObs,Reward,IsDone,NextState] = myStepFunction2(Action,State,EnvPars)
% Custom step function to construct cart-pole environment for the function
% handle case.
%
% This function applies the given action to the environment and evaluates
% the system dynamics for one simulation step.

% Check if the given action is valid.
if ~ismember(Action,[-EnvPars.MaxForce EnvPars.MaxForce])
    error('Action must be %g for going left and %g for going right.',...
        -EnvPars.MaxForce,EnvPars.MaxForce);
end
Force = Action;

% Unpack the state vector from the logged signals.
XDot = State(2);
Theta = State(3);
ThetaDot = State(4);

% Cache to avoid recomputation.
CosTheta = cos(Theta);
SinTheta = sin(Theta);
MassPole = EnvPars.MassPole;
HalfLen = EnvPars.HalfLength;
SystemMass = EnvPars.MassCart + MassPole;
temp = (Force + MassPole*HalfLen*ThetaDot*ThetaDot*SinTheta)/SystemMass;

% Apply motion equations.
ThetaDotDot = (EnvPars.Gravity*SinTheta - CosTheta*temp)...
    / (HalfLen*(4.0/3.0 - MassPole*CosTheta*CosTheta/SystemMass));
XDotDot  = temp - MassPole*HalfLen*ThetaDotDot*CosTheta/SystemMass;

% Perform Euler integration.
NextState = State + EnvPars.Ts.*[XDot;XDotDot;ThetaDot;ThetaDotDot];

% Copy next state to next observation.
NextObs = NextState;

% Check terminal condition.
X = NextObs(1);
Theta = NextObs(3);
IsDone = abs(X) > EnvPars.XThreshold || ...
         abs(Theta) > EnvPars.ThetaThresholdRadians;

% Calculate reward.
if ~IsDone
    Reward = EnvPars.RewardForNotFalling;
else
    Reward = EnvPars.PenaltyForFalling;
end

end

環境パラメーターを格納する構造体を作成します。

% Acceleration due to gravity in m/s^2
envPars.Gravity = 9.8;
% Mass of the cart
envPars.MassCart = 1.0;
% Mass of the pole
envPars.MassPole = 0.1;
% Half the length of the pole
envPars.HalfLength = 0.5;
% Max force the input can apply
envPars.MaxForce = 10;
% Sample time
envPars.Ts = 0.02;
% Angle at which to fail the episode
envPars.ThetaThresholdRadians = 12 * pi/180;
% Distance at which to fail the episode
envPars.XThreshold = 2.4;
% Reward each time step the cart-pole is balanced
envPars.RewardForNotFalling = 1;
% Penalty when the cart-pole fails to balance
envPars.PenaltyForFalling = -5;

カスタム ステップ関数を呼び出す無名関数を作成し、追加の入力引数として envPars を渡します。

StepHandle = @(Action,Info) myStepFunction2(Action,Info,envPars);

envParsStepHandle の作成時に使用可能なため、無名関数ワークスペースには envPars のコピーが含まれます。StepHandle が評価されると、myStepFunction2 が呼び出され、envPars のコピーが渡されます。

同じ関数 reset を、名前ではなく関数ハンドルとして指定し、それを使用します。

ResetHandle = @() myResetFunction;

無名関数へのハンドルを使用して環境を作成します。

env2 = rlFunctionEnv(ObsInfo,ActInfo,StepHandle,ResetHandle);

カスタム関数の出力の視覚的な検証

rlFunctionEnv は環境の作成後に自動的にvalidateEnvironmentを呼び出しますが、関数の出力を視覚的に検証して、関数の動作が期待どおりであることをさらに確認すると便利な場合があります。これを行うには、関数 reset を使用して環境を初期化し、関数 step を使用して 1 つのシミュレーション ステップを実行します。再現性をもたせるために、検証前に乱数発生器のシードを設定します。

関数名を使用して作成された環境を検証します。

rng(0);
InitialObs = reset(env)
InitialObs = 4×1

         0
         0
    0.0315
         0

[NextObs,Reward,IsDone,Info] = step(env,10);
NextObs
NextObs = 4×1

         0
    0.1947
    0.0315
   -0.2826

関数ハンドルを使用して作成された環境を検証します。

rng(0);
InitialObs2 = reset(env2)
InitialObs2 = 4×1

         0
         0
    0.0315
         0

[NextObs2,Reward2,IsDone2,Info2] = step(env2,10);
NextObs2
NextObs2 = 4×1

         0
    0.1947
    0.0315
   -0.2826

両方の環境が正常に初期化およびシミュレーションされ、NextObs に同じ状態値が生成されています。

参考

関数

オブジェクト

関連するトピック