ランド研究所の「機械学習による航空支配」を実装する（その１５）： 2D問題 mission_2

#1. はじめに

本記事は、ランド研究所の「機械学習による航空支配」を実装する（その１５）です。

[Air Dominance Through Machine Learning: A Preliminary Exploration of Artificial Intelligence–Assisted Mission Planning, 2020](https://www.rand.org/pubs/research_reports/RR4311.html)


今回から 強化学習ライブラリは、[Stable Baselines](https://stable-baselines.readthedocs.io/en/master/) の代わりに、[RLLIB](https://docs.ray.io/en/master/rllib.html) を使用することにしました。実は、このプログラミングの前に、1D 問題の GAN ＋強化学習をやったのですが、Stable Baselines が Tensorflow 1 にしか対応していなかったので、RLLIB を使うハメになりました。このため、2D 問題でも、Tensorflow 2 を使うことになるかもしれないので、乗り換えました。ふらふらしてゴメンナサイ。幸い、Stable Baselines も RLLIB も、高度な機能を使用しないのであれば、学習コードはほとんど同じです。

今回使用したコードは、下記 GitHub の 'mission_2' フォルダです。強化学習アルゴリズムは、[SAC](https://arxiv.org/abs/1801.01290) を用いました。

>https://github.com/DreamMaker-Ai/AirDominance_2D_RL

#2. Mission 2

ミッション２の登場人物（エンティティ）は以下の通りとします。

```
Blue Team:
 Fighter x 1

Red Team:
 SAM (stationary) x 1
 Target (stationary) x 1
```

ミッション２は、Fighter 1 機を使って Target を攻撃するミッションです。原理検証（PoC: Proof of Concept）なので、学習の成否判断が出来るように、学習が上手くできればミッション成功率が 100% になるよう各エンティティの位置や射程を設定しました。具体的には、

- Target は、SAM に防護されている（SAM の射程内に Target が存在する）場合もあれば、SAM には防護されていない（SAM の射程外に Target が存在する）場合もある。
- Target には防護能力は無い。したがって、Fighter 搭載ウェポンの射程内に Target が入った場合、100% 確実に Target は破壊される。
- Fighter 搭載ウェポンの射程は、SAM の射程よりも長い時もあれば、SAM の射程よりも短い時もある。ただし、いずれの場合でも、プランさえうまく組めば Target を破壊できるだけの射程は持っている（つまり、ミッションが成立する）。

ミッション目的は、以下の２通りを考えます。

```
Mission 2A: 目的は、あくまで Target の破壊であり、SAM の破壊は特に必要ではない。
Mission 2B: 主目的は、Target の破壊であるが、Fighter 搭載ウェポンの射程が SAM の射程よりも長い時は、無理が無い範囲で SAM を破壊する。
```

いずれのミッションにおいても、Target が破壊されたらミッション終了とします。（したがって、SAM を破壊する時は、Target よりも前に破壊する必要があります）。


#3. 相対観測量

相対観測量は、距離と角度を使って下図の量としました。これにより、下図を慣性空間上で並行移動したり、回転移動したりしても、同一の観測量が得られるため、慣性座標系で観測量を定義するよりも、観測空間がずっと小さくて済みます。

図３．１
![Mission_2_eng.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/216f6755-fd4b-a711-ff40-2078085a48f5.png)

この場合、観測量は以下の 19 次元になります。

![observation list.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/0895845d-d246-22d2-4cbe-97b4125c607f.jpeg)



コードでは以下になっています。

    def get_relative_observation_mission_2(self):
        obs = []
        r = (self.space_x ** 2 + self.space_y ** 2) ** 0.5

        v_f = self.make_v(self.fighter_1)
        r_fs = self.make_r(self.sam_1, self.fighter_1)
        sin_fs, cos_fs = self.compute_heading_error(v_f, r_fs)

        r_ft = self.make_r(self.target_1, self.fighter_1)
        sin_ft, cos_ft = self.compute_heading_error(v_f, r_ft)

        r_st = self.make_r(self.target_1, self.sam_1)
        sin_s, cos_s = self.compute_heading_error(r_fs, r_st)
        sin_t, cos_t = self.compute_heading_error(r_ft, r_st)

        obs.append(sin_fs)
        obs.append(cos_fs)
        obs.append(np.linalg.norm(r_fs, ord=2) / r)
        obs.append(sin_ft)
        obs.append(cos_ft)
        obs.append(np.linalg.norm(r_ft, ord=2) / r)
        obs.append(sin_s)
        obs.append(cos_s)
        obs.append(sin_t)
        obs.append(cos_t)
        obs.append(np.linalg.norm(r_st, ord=2) / r)

        # print(self.fighter_1.firing_range / self.fighter_1.max_firing_range)
        obs.append(self.fighter_1.firing_range / self.fighter_1.max_firing_range)
        obs.append(self.fighter_1.weapon_count)
        obs.append(self.fighter_1.alive)

        # print(self.sam_1.firing_range / self.sam_1.max_firing_range)
        obs.append(self.sam_1.firing_range / self.sam_1.max_firing_range)
        obs.append(
            self.sam_1.jammed_firing_range / (self.sam_1.max_firing_range * self.jammer_1.jam_effectiveness))
        obs.append(self.sam_1.weapon_count)
        obs.append(self.sam_1.alive)

        obs.append(self.target_1.alive)

        return obs


#4. 学習条件

Target は静止しているものとし、戦場中心 (50, 50) km に配置します。SAM は Target から半径[15,20] km のリング内の任意の位置とします。これにより、SAM は、その射程に応じて Target を防護している時もあれば、防護していない時もあることになります。

Fighter の初期位置は、SAM から半径 [45, 50] km のリング内の任意の位置とします。Fighter のヘディングエラーについては、ミッション１で、非常にロバストなことが判ったので、今回はヘディングエラー無しの条件だけでトレーニングし、ロバスト性を測ることにしました。これらを絵で描くと下図になります。

図４．１
![Engagement geometry for training ID=1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/16dd91a3-00d4-172f-d528-b085ff36764d.png)

この場合、ミッションとしては、Fighter と SAM の射程によって、以下の２タイプが考えられます。

```
mission_type_1: fighter.firing_range > sam.firing_range
mission_type_2: fighter.firing_range < sam.firing_range
```

mission_type_1 の場合は SAM と Target の撃破が可能ですが、mission_type_2 の場合は、SAM の撃破は不可能ですので、SAM を迂回して Target を撃破することが必要です。

プランナーは、与えられたミッション条件から、これを加味してプランを生成します。これらのミッション・タイプについては、学習時には、どちらか一方のタイプにだけバイアスがかからないように、

```
mission_type_1 のトレーニング数：mission_type_2 のトレーニング数 = １：１
```

となるように、ミッションタイプをランダムに選択してトレーニングしました。

トレーニング時の報酬については、次の２通りを試すことで、Planner 1, Planner 2 の２種類のエージェントをトレーニングし、性質の違いを見ることにしました。

```Planner 1```: Target を撃破した時のみ報酬１を与えてトレーニング。SAM を撃破しても報酬は与えない。したがって、あるエピソードの最大報酬は１。これは、ミッション目的 2A を達成することを企図したプランナーになります。

```Planner 2```: SAM を撃破した時に報酬１、Target を撃破した時にも報酬１。したがって、あるエピソードの最大報酬は２。この場合、Agent（プランナー）は、SAM と Target の両方を破壊するインセンティブが与えられるので、ミッション目的 2B を達成することを企図したプランナーになります。ただし、今回の学習では、Target を破壊したら、そのエピソードは終了なので、SAM はターゲットより前に破壊する必要があります。（ここは、エピソードの終端条件をどう設定するのかに依ります）。この場合、Planner 1 よりも学ぶべき内容が多くなるので、学習にはより時間がかかるようになるはずです。

Planner 2 の場合、コードでは次のよう報酬を与えます。

    def get_reward_mission_2(self, done, fighter, sam, target):
        reward = 0

        # For destroy sam
        if (sam.alive < .5) and (sam.previous_alive > .5):
            reward += 1

        # For done
        if done:
            """
            if (self.fighter_1.alive > .5) and (self.target_1.alive < .5):
                if (self.fighter_1.firing_range > self.sam_1.firing_range) and (self.sam_1.alive < .5):
                    reward = 1
                elif self.fighter_1.firing_range < self.sam_1.firing_range:
                    reward = 1
            """
            if self.target_1.alive < .5:
                reward += 1
            else:
                reward = -1

        return reward

Planner 1 では、エピソード報酬の最大値は 1 ですので、ミッション条件が mission_type_1 であっても、mission_type_2 であっても、planner-1 の学習がうまく進んだ場合の平均報酬（期待報酬）は 1 になります。

一方、Planner 2 では、ミッション条件が mission_type_1 の時のエピソード報酬の最大値は 2、mission_type_2 の時のエピソード報酬の最大値は 1 です。学習時には、mission_type_1、mission_type_2 を１：１の比率でランダムに選択して学習させているので、学習がうまく進んだ場合の平均報酬（期待報酬）は約 1.5 になります。


#5. 学習履歴

planner-1 と planner-2 のエピソード報酬の平均値の履歴をしまします。橙色のラインが planner-1（SAM 撃破時の報酬無し、学習成功時の平均エピソード報酬 = 1）、茶色のラインが planner-2（SAM撃破時の報酬有り、学習成功時の平均エピソード報酬 = 1.5） に対応します。

予想通り、planner-2 の時のほうが学習に（平均報酬=1.5になるのに）時間がかかりますが、どちらのケースであっても学習は成功しています。

図５．１
![episode reward mean_trial_1 & 3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/9f4f917a-cbb9-b923-4ac8-731f2399ecba.jpeg)

下図は、学習時の平均エピソード長です。Fighter と SAM の初期離隔は[45,50]km、resolution（タイムステップでの Fighter の移動距離=.5km) なので、Fighter の射程分も考慮すると学習後のエピソード長は 100 以下になることが期待できます。平均報酬が急に増加するタイミングで、エピソード長が急に短くなっているのはこのためです。

図５．２
![episode length mean_trail_1 & 3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/3e76f0ae-92fe-18e0-cd9e-9a715a8535a6.jpeg)


下図は、planner-1 の学習中のエピソード報酬の分布を示したものです。横軸が報酬の分布、縦軸がトレーニングステップです。学習が進むに連れて、報酬の分布が１の方に移動していく様子が判ります。

図５．３
![trial_1_episode_reward.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/6f350d33-3789-fa8e-aaf0-1a43e0b655e7.png)

planner-1 学習中のエピソード長は下図のように分布しました。学習が進むと、短いエピソード長で対応できるようになります。

図５．４
![trial_1_episodes_length.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/c34ff319-4149-2e16-7ec9-a25657145d24.png)



下図は、planner 2 の学習中のエピソード報酬の分布を示したものです。

図５．５
![trial_3_episode_reward.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/a0204e35-38de-1266-1b8a-35b99335bb9a.png)


下図は、planner-2 の学習中のエピソード長の分布を示したものです

図５．６
![trial_3_episode_length.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/fe2a1d88-7582-fd60-feda-dcbfe910f9af.png)


下図は、planner-1 と planner-2 のプランの特性の違いを見るために、、どういった形でミッションに失敗／成功し得るのかを分類したものです。mission_type_1（Fighter 搭載ウェポンの射程が SAM の射程よりも長い時）では、一言にミッション成功（＝ Target 撃破）と言っても、SAMを撃破しているケース（下図 S1）と SAM を撃破していないケース（下図 S2）があります。一方、mission_type_2（Fighter 搭載ウェポンの射程がSAM の射程よりも短い時）では、SAMは撃破不可能なミッション条件なので、ミッション成功の類型は S3 の一通りのみになります。

図５．７
![F-S table.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/d4c308cb-9a1d-a338-4e28-b3811dccc494.jpeg)

トレーニング時のこの内訳を Planner-1 について書いたのが下図になります。縦軸がミッション成功率[%]、横軸がトレーニング回数です。

図５．８
![trial_1_learning_history.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/71e2bee6-e01b-85a3-7bd7-878e49f781c9.png)

Planner-2 に対しては下図になります。Planner-1 と Planner-2 を比べると、学習が進むに連れて、成功率はどちらも約 100% を達成していますが、S1 と S2 の割合に大きな違いがみられます。SAM 撃破時に報酬を与えられて学習した planner-2 では、SAM を撃破してからターゲットを撃破する S1 の形の成功が多くなるように学習が進みます。（今回の学習では、Targetを破壊したら、そのエピソードは終了なので、SAMはターゲットより前に破壊する必要があります）。

図５．９
![trial_3_learning_history.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/5c9fa569-0145-820c-b647-87b26175af52.png)


学習した planner_1, planner_2 に、mission_type_1 (fighter.firing_range > sam.firing_range) のミッションをランダムに与えた時に、各プランナーが生成したプランがミッションに成功した割合を成功率として示したのが下図になります。random planner に比べると、planner_1, planner_2ともに成功率100％と向上していますが、その内訳である S1, S2 の比率には大きな違いがあります。当然ですが、SAMの破壊にインセンティブを与えるよう報酬を与えてトレーニングした Planner 2 では SAM を破壊する割合 S1 が大きくなっています。Planner 2 の学習を続けていくと S1 の形の成功がさらに増えていくのか、この辺りで飽和するのかは判りませんが、少なくともここでトレーニングをストップした場合は、（後出の生成プラン例で示すように）、SAM の破壊に無理があるような初期位置関係（Fighter から見て、SAM が Target の逆向こうにある）の場合、SAM の破壊を強行するようなプランは生成していませんでした。

図５．１０
![Breakdown of Success _ Fail [%].png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/ef669c2d-1be1-32f5-5181-a3c2e4fbff49.png)


mission_type_2 (fighter.firing_range < sam.firing_range) の場合の、各プランナーの成功率は下図になります。成功率は、ほぼ100％でした。

図５．１１
![Breakdown of Success _ Fail [%] (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/c4bb7d46-4386-b41b-5f13-03e259420fbf.png)


##5.1 生成プラン例　Planner_1
始めに、SAMの破壊にインセンティブを与えていないプランナーのミッション生成例を示します。

以下の動画では、濃紺の丸が Fighter、半透明で濃紺の大きな円が Fighter の射程、赤の丸が SAM 配備位置 、半透明で赤色の大きな円が SAM の射程、ピンクの丸がTarget を表しています。Target が、Fighter の射程に入ったらミッション成功でエピソード終了です。

###5.1.1 S1

S1のタイプのミッションプランを生成した例を示します。Fighter が Target に向かう直線経路の近くに SAM がある場合、少しだけ寄り道をしてSAMを破壊した後に Target を撃破するプランです。SAM の破壊にインセンティブを与えていないにもかかわらず、なぜ寄り道をしてまで SAM を破壊するプランを生成するのかは、いろいろ考えたのですが判りません。不思議です。Target を破壊すると報酬がもらえるので、何かを破壊することが快感になるのでしょうか？ここは、興味深いポイントなので、その内、もう少し考えてみたいと思います。

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S1",
  "fighter_1": {
    "alive": 1,
    "firing_range": 6.5
  },
  "sam_1": {
    "alive": 0,
    "firing_range": 5.0
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S1_20.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/08759ffd-bc0a-2319-ac12-f6c3631adc00.gif)


```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S1",
  "fighter_1": {
    "alive": 1,
    "firing_range": 20.0
  },
  "sam_1": {
    "alive": 0,
    "firing_range": 13.0
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S1_48.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/cac4c0a2-6d9f-70da-a069-9aba47e13373.gif)


###5.1.2 S2

S2 のタイプのミッションプランの生成例です。SAMは無視して、直接Targetを撃破するプランを生成します。

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S2",
  "fighter_1": {
    "alive": 1,
    "firing_range": 14.5
  },
  "sam_1": {
    "alive": 1,
    "firing_range": 5.0
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S2_1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/72948fe1-2450-d86f-461e-055e5c9e98dd.gif)


```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S2",
  "fighter_1": {
    "alive": 1,
    "firing_range": 14.5
  },
  "sam_1": {
    "alive": 1,
    "firing_range": 12.5
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S2_35.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/72cb9110-5df2-ed1e-e6c7-35b981bfbea6.gif)



###5.1.3 S3

```Fighter搭載ウェポンの射程 ＜ SAMの射程```なので、Fighter初期位置とTargetの間にSAMが位置する場合、SAMの射程のエンベロープを回り込むプランを生成する必要があります。この動きは、なんとなく人間っぽい気がします。

まずは、TargetがSAMの射程外で防護されていないミッション条件の場合です。

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S3",
  "fighter_1": {
    "alive": 1,
    "firing_range": 10.0
  },
  "sam_1": {
    "alive": 1,
    "firing_range": 14.5
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S3_0.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/3478d54d-a379-eedd-255a-5c85f77d295a.gif)


次に、TargetがSAMの射程内に位置し、SAMに防護されているミッション条件の場合を示します。


```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S3",
  "fighter_1": {
    "alive": 1,
    "firing_range": 12.0
  },
  "sam_1": {
    "alive": 1,
    "firing_range": 20.5
  },
  "target_1": {
    "alive": 0
  }
}
```


![sac_S3_15.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/def97308-f541-14bc-4ea6-8094bbbd8897.gif)



##5.2 生成プラン例　Planner_2
以下の動画では、濃紺の丸が Fighter、半透明で濃紺の大きな円が Fighter の射程、赤の丸が SAM 配備位置 、半透明で赤色の大きな円が SAM の射程、ピンクの丸がTarget を表しています。

Targetよりも先にSAMを撃破し、その後Targetを撃破すると、最大額の報酬２が得られるようトレーニングしたプランナーです。

###5.2.1 S1

TargetとSAMを、ほぼ同時に捕らえられるようなミッション条件では、同時に同時に撃破できるようなプランを生成します。

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S1",
  "fighter_1": {
    "alive": 1,
    "firing_range": 20.5
  },
  "sam_1": {
    "alive": 0,
    "firing_range": 18.5
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S1_7.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/e69c75b8-ee54-a6e7-848b-ac388333e185.gif)

TargetとSAMを同時に撃破できないミッション条件では、先にTargetを回り込んでSAMを撃破してから、Targetを撃破するプランを生成します。

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S1",
  "fighter_1": {
    "alive": 1,
    "firing_range": 8.0
  },
  "sam_1": {
    "alive": 0,
    "firing_range": 4.5
  },
  "target_1": {
    "alive": 0
  }
}
```


![sac_S1_4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/82dca339-db4a-b26b-28fa-8bfdcd74db23.gif)

Fighter 初期位置と Target の間に SAM が位置する場合でも、Target と SAM を、ほぼ同時に捕らえられるようなミッション条件では、同時に捕らえるようなプランを生成します。


```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S1",
  "fighter_1": {
    "alive": 1,
    "firing_range": 20.5
  },
  "sam_1": {
    "alive": 0,
    "firing_range": 17.0
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S1_20.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/a24e926d-b944-cdce-bc5c-7273c90be737.gif)



###5.2.2 S2

ミッションの初期条件が、Target よりも先に SAM を撃破することが、あまりにも非効率な場合（Target の真反対に SAM が位置するような場合）は、SAM を撃破せずに Target を撃破するプランを生成します。

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S2",
  "fighter_1": {
    "alive": 1,
    "firing_range": 21.0
  },
  "sam_1": {
    "alive": 1,
    "firing_range": 12.5
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S2_29.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/8209574a-71a0-48ed-21a5-fd465249d612.gif)



###5.2.3 S3

Fighter 搭載ウェポンの射程が SAM の射程よりも短い時は、回り込んで Target を撃破します。


```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S3",
  "fighter_1": {
    "alive": 1,
    "firing_range": 10.0
  },
  "sam_1": {
    "alive": 1,
    "firing_range": 16.5
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S3_3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/ed8d8dbb-2383-7ee7-c9cb-286d7a8487a9.gif)


```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S3",
  "fighter_1": {
    "alive": 1,
    "firing_range": 7.5
  },
  "sam_1": {
    "alive": 1,
    "firing_range": 8.5
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S3_26.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/8b32aaf5-cf51-a8f4-87d1-9ee1d67075a4.gif)



#6. プランナーの汎化能力（エージェントのロバストネス）

学習時に経験したミッション条件の外側（外挿する側）にあるミッション条件に対し、生成したプランの成功率を調べることで、Planner 1, Planner 2 のロバスト性を確認します。確認条件は以下の通りです。

 - fighter position: Fighter 初期位置の変動に対するプランナーのロバスト性を測るために、Fighter 初期位置を Target から、[90,100]km とて実験しました。（学習時は、[45,50] km です）。
 
 - heading error ±90 deg, ±180 deg: Fighter 初期ヘディングエラーの変動に対するはプランナーのロバスト性は、±90度のケースと、±180度のケースで確認しました。（学習時は、初期ヘディングエラー＝０のみです。）

 - fighter position + heading error ±180 deg: Fighter の初期位置とヘディングエラーが同時に変動した時のプランナーのロバスト性を測りました。初期位置は Targetから [80,20km], ヘディングエラー変動は　±180 degです。

 - fighter position + heading error ±180 deg + sam position: さらに、SAM と Target 位置の離隔変動に対するプランナーのロバスト性を測りました。Fighterの初期位置は Targetから [80,20km], Fighterのヘディングエラー変動は　±180 deg、SAM位置は Targetから [20,50] km です。


以下に、planner 1 の```fighter の射程 > SAM の射程```の場合のロンバスト性を示します。非常にロバストであることが判ります。

図６．１
![Planner #1_ Robustness to initial conditions.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/c8e8a805-c2bc-5d6f-d0e0-8494c5978052.png)

以下に、planner 1 の```fighter の射程 < SAM の射程```の場合のロンバスト性を示します。非常にロバストであることが判ります。

図６．２
![Planner #1_ Robustness to initial conditions (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/62fa77d0-39f1-bc65-f3b0-746ec260b95b.png)

以下に、planner 2 の```fighter の射程 > SAM の射程```の場合のロンバスト性を示します。非常にロバストであることが判ります。また、SAM を撃破するプラン S1 の割合もあまり変動していませんでした。

図６．３
![Planner #2_ Robustness to initial conditions.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/da747d71-2989-2ccf-bf4c-17045b78a996.png)

以下に、planner 2 の```fighter の射程 < SAM の射程```の場合のロンバスト性を示します。非常にロバストであることが判ります。

図６．４
![Planner #2_ Robustness to initial conditions (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/bc3abe85-2070-9ba7-2444-fac6ce8372dc.png)


##6.1 生成プラン例　range robustness
私のエネルギー不足もあり、また、見ればわかると思いますので、説明は省略します（ゴメンナサイ）が、以下に、学習時に経験したミッション条件の外挿条件で生成したプランの例を示します。

以下の動画では、濃紺の丸が Fighter、半透明で濃紺の大きな円が Fighter の射程、赤の丸が SAM 配備位置 、半透明で赤色の大きな円が SAM の射程、ピンクの丸がTarget を表しています。Target が、Fighter の射程に入ったらミッション成功でエピソード終了です。

ミッション結果の類型：S1, S2, S3,F1, F2 の表を再録しておきます。

![F-S table.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/d4c308cb-9a1d-a338-4e28-b3811dccc494.jpeg)

###6.1.1 Planner 1
#### 6.1.1.1 S1

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S1",
  "fighter_1": {
    "alive": 1,
    "firing_range": 21.0
  },
  "sam_1": {
    "alive": 0,
    "firing_range": 19.0
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S1_12.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/de62e7b9-68af-0086-0d4e-52f3aafa456f.gif)



#### 6.1.1.2 S2

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S2",
  "fighter_1": {
    "alive": 1,
    "firing_range": 14.0
  },
  "sam_1": {
    "alive": 1,
    "firing_range": 11.0
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S2_16.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/e3720495-6957-afe9-9c17-cad3a8de5db3.gif)


#### 6.1.1.3 S3

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S3",
  "fighter_1": {
    "alive": 1,
    "firing_range": 19.5
  },
  "sam_1": {
    "alive": 1,
    "firing_range": 21.0
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S3_21.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/6d83b176-402c-bc01-8c3a-fc89feab522d.gif)

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S3",
  "fighter_1": {
    "alive": 1,
    "firing_range": 11.5
  },
  "sam_1": {
    "alive": 1,
    "firing_range": 18.5
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S3_24.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/7500b647-9bd4-e7c9-f1c1-01c03635394c.gif)


###6.1.2 Planner 2
#### 6.1.2.1 S1

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S1",
  "fighter_1": {
    "alive": 1,
    "firing_range": 19.0
  },
  "sam_1": {
    "alive": 0,
    "firing_range": 18.0
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S1_6.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/c3cbce13-cb87-63ca-0474-ae84f1445e71.gif)

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S1",
  "fighter_1": {
    "alive": 1,
    "firing_range": 17.0
  },
  "sam_1": {
    "alive": 0,
    "firing_range": 16.0
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S1_9.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/5dd358d1-4860-c0e0-5b01-00e8aa1fbeb0.gif)

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S1",
  "fighter_1": {
    "alive": 1,
    "firing_range": 12.0
  },
  "sam_1": {
    "alive": 0,
    "firing_range": 9.5
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S1_14.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/fffa88eb-5672-4da8-64bc-3c5a5632612a.gif)



#### 6.1.2.2 S3

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S3",
  "fighter_1": {
    "alive": 1,
    "firing_range": 14.5
  },
  "sam_1": {
    "alive": 1,
    "firing_range": 20.0
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S3_7.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/2135dc7e-1c8f-294f-55bc-e472112f476a.gif)

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S3",
  "fighter_1": {
    "alive": 1,
    "firing_range": 9.5
  },
  "sam_1": {
    "alive": 1,
    "firing_range": 18.5
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S3_8.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/0eb89bf2-8566-f01f-9c31-e71af4a66e54.gif)



##6.2 生成プラン例　range + heading error + SAM location robustness
###6.2.1 Planner 1
#### 6.2.1.1 S1

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S1",
  "fighter_1": {
    "alive": 1,
    "firing_range": 12.0
  },
  "sam_1": {
    "alive": 0,
    "firing_range": 4.0
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S1_0.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/75e1b56d-1d22-04b9-4fcc-b04e9b93a909.gif)


#### 6.2.1.2 S2

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S2",
  "fighter_1": {
    "alive": 1,
    "firing_range": 10.5
  },
  "sam_1": {
    "alive": 1,
    "firing_range": 4.5
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S2_6.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/a732c8cd-f9a5-08cb-313b-bafa457a2889.gif)

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S2",
  "fighter_1": {
    "alive": 1,
    "firing_range": 21.0
  },
  "sam_1": {
    "alive": 1,
    "firing_range": 20.5
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S2_19.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/927895ff-dc44-d3d1-f6dd-f38a07e0776c.gif)


#### 6.2.1.3 S3

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S3",
  "fighter_1": {
    "alive": 1,
    "firing_range": 20.0
  },
  "sam_1": {
    "alive": 1,
    "firing_range": 20.5
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S3_11.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/90413fff-53d3-e87c-96fd-68ce83bee3d0.gif)

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S3",
  "fighter_1": {
    "alive": 1,
    "firing_range": 16.0
  },
  "sam_1": {
    "alive": 1,
    "firing_range": 17.5
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S3_37.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/f507f665-aa11-026f-e578-090917175ea9.gif)


###6.2.2 Planner 2
#### 6.2.2.1 S1

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S1",
  "fighter_1": {
    "alive": 1,
    "firing_range": 8.0
  },
  "sam_1": {
    "alive": 0,
    "firing_range": 4.5
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S1_7.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/2d572b44-de9f-a033-1898-7c496f4fcb23.gif)

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S1",
  "fighter_1": {
    "alive": 1,
    "firing_range": 20.0
  },
  "sam_1": {
    "alive": 0,
    "firing_range": 15.0
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S1_16.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/e569472d-efb9-2aa2-6121-88cef91acae7.gif)


#### 6.2.2.2 S2

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S2",
  "fighter_1": {
    "alive": 1,
    "firing_range": 7.0
  },
  "sam_1": {
    "alive": 1,
    "firing_range": 4.5
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S2_14.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/10ecead9-5d31-c276-29f7-f91119cb1f1e.gif)

#### 6.2.2.3 S3

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S3",
  "fighter_1": {
    "alive": 1,
    "firing_range": 7.0
  },
  "sam_1": {
    "alive": 1,
    "firing_range": 18.0
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S3_12.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/4dd35b88-5d09-57ae-38f3-3abba7afc0e2.gif)

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "S3",
  "fighter_1": {
    "alive": 1,
    "firing_range": 7.5
  },
  "sam_1": {
    "alive": 1,
    "firing_range": 10.0
  },
  "target_1": {
    "alive": 0
  }
}
```

![sac_S3_29.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/6ba57b0c-0fab-5a0c-c537-a67b801f4756.gif)


#### 6.2.2.4 F2

失敗プランの例です。Fighter は、最初Targetを指向しているのですが、途中から SAM に吸い寄せられるように接近してしまい撃破されました。Fighter 初期位置が、外挿の大きな条件の時に、なぜ Target と SAM を取り違えるミスが発生するのでしょうか？これも興味深い謎です。

```
{
  "mission_id": "mission_2",
  "mission_condition": "m1",
  "result": "F2",
  "fighter_1": {
    "alive": 0,
    "firing_range": 10.0
  },
  "sam_1": {
    "alive": 1,
    "firing_range": 10.5
  },
  "target_1": {
    "alive": 1
  }
}
```

![sac_F2_4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366937/6a7b0753-3ad5-ec5e-bfdc-0813b0c95c64.gif)



#7.まとめ
汎化能力が高いロバストなプランナーが学習できました。


#（その１６）へ続く
（その１６）では、３機のFighterでSAM１基を攻撃するミッション（但し、3機の内1機のみが、SAMの射程よりも長いウェポンを搭載）について学習します。


#過去記事へのリンク
- [ランド研究所の「機械学習による航空支配」を実装する（その1）：レポートのまとめ](https://qiita.com/DreamMakerAi/private/95e0aad16e450cb0c53d)
- [ランド研究所の「機械学習による航空支配」を実装する（その2）：1次元問題について](https://qiita.com/DreamMakerAi/items/72c90f9df5339dedd9cd)
- [ランド研究所の「機械学習による航空支配」を実装する（その3）： 1D simulator for GAN と Random mission planner の実装）](https://qiita.com/DreamMakerAi/private/1a0e25a9f673e531ee6f)
- [ランド研究所の「機械学習による航空支配」を実装する（その4）： conditional GAN の実装とトレーニング](https://qiita.com/DreamMakerAi/private/3a416d5cb64d9b7e86db)
- [ランド研究所の「機械学習による航空支配」を実装する（その5）：トレーニング結果の分析](https://qiita.com/DreamMakerAi/items/6c78181b71c470632fcf)
- [ランド研究所の「機械学習による航空支配」を実装する（その６）：トレーニング・データの重要性と GAN の性能向上](https://qiita.com/DreamMakerAi/private/b8ae6c9afd28e90b5b5c)
- [ランド研究所の「機械学習による航空支配」を実装する（その７）：1D simulator for RL の実装](https://qiita.com/DreamMakerAi/private/f008fa9981c3ad74c3cc)
- [ランド研究所の「機械学習による航空支配」を実装する（その８）： Stable Baselines による強化学習](https://qiita.com/drafts/37e6a18810b83d759d81/edit)
- [ランド研究所の「機械学習による航空支配」を実装する（その９）： 少し複雑な環境](https://qiita.com/DreamMakerAi/private/f4d3e35c07ab053608ea)
- [ランド研究所の「機械学習による航空支配」を実装する（その１０）：GAN / 強化学習プランナーの連携を考える](https://qiita.com/DreamMakerAi/private/6cb416e42fc35a7a425c)
- [ランド研究所の「機械学習による航空支配」を実装する（その１１）： ２次元問題の概要](https://qiita.com/DreamMakerAi/private/3572afde356ba5719123)
- [ランド研究所の「機械学習による航空支配」を実装する（その１２）： 2D simulator for mission_1 の実装](https://qiita.com/DreamMakerAi/private/af22d730bf8cbff23fdd)
- [ランド研究所の「機械学習による航空支配」を実装する（その１３）： 2D 問題 mission_1 を強化学習する](https://qiita.com/DreamMakerAi/private/2922e4ad82e8e8c2a059)
- [ランド研究所の「機械学習による航空支配」を実装する（その１４）： Relative Observation による mission planner の能力アップ](https://qiita.com/DreamMakerAi/private/fb2b9971c0894d4cc49b)