{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Lyft: データの理解とEDA"},{"metadata":{},"cell_type":"markdown","source":"### クレジット:\n\n**https://www.kaggle.com/t3nyks/lyft-working-with-map-api**<br>\n**https://www.kaggle.com/jpbremer/lyft-scene-visualisations**<br>\n**https://www.kaggle.com/pestipeti/pytorch-baseline-train**"},{"metadata":{},"cell_type":"markdown","source":"注釈：\n本記事は https://www.kaggle.com/nxrprime/lyft-understanding-the-data-baseline-model を日本語に訳したものになります。\n内容の誤りや誤訳については予めご容赦ください。\n\nこの新しいLyftのコンペは、参加者である私たちに、自動車や自転車、歩行者などの動きを予測して、自動運転車を支援することを課題としています。昨年のコンペでは、ストップサインなどの立体物を検知して自動運転車に認識方法を教えるという課題がありましたが、これは一歩前進しています。"},{"metadata":{},"cell_type":"markdown","source":"これは明らかに**最大の交通エージェントのモーションデータのコレクションです。**ファイルはPythonで.zarrファイル形式で保存されています。トレーニングZARRの中には、エージェント、エージェント用マスク、フレームとシーン、信号機があります。\n\nテスト用ZARRはほぼ同じフォーマットですが、データマスクが除外されているだけです。"},{"metadata":{},"cell_type":"markdown","source":"## データの利用を開始する"},{"metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"cell_type":"code","source":"!pip install --upgrade pip\n!pip install pymap3d==2.1.0\n!pip install -U l5kit","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"待ってください！可視化とそれに伴うすべての処理に入る前に、短いYouTubeのビデオを見て、自律走行車の操作の主題について知りませんか？"},{"metadata":{"trusted":true},"cell_type":"code","source":"from IPython.display import HTML\nHTML('<center><iframe width=\"700\" height=\"400\" src=\"https://www.youtube.com/embed/tlThdr3O5Qo?rel=0&amp;controls=0&amp;showinfo=0\" frameborder=\"0\" allowfullscreen></iframe></center>')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"この車は、ドライバーが直面する通常の課題をさりげなくこなしているように見えます。それも驚くほどの精度です。ここでは、このようなことを実現するために、外部要因の動きを予測し、それに基づいて自動運転車の動きの経路を予測することが課題となっています***このような外部要因の動きを予測するためには、後述するように様々なアプローチがありますが、とりあえず飛び込んでみましょう。\n\nここでは、データセットとその内容についての簡単なFAQを紹介します。\n\n**データセットの構造は？**<br>\nデータセットは以下のように構成されています。\n```\naerial_map\nscenes\nsemantic_map\n```\n\nここでは、各シーンには、複数の外部車両の動きとそれに対応する自動運転車の動きに関する情報が約1分程度含まれています。\n\nデータ一覧:\n```\nsample.zarr\ntest.zarr\ntrain.zarr\nvalidate.zarr\n```\n\n今、このZARRフォーマットは、私は参加者のほとんどがこれらを使用したことがないと思っているので、少し興味深いです。これらはNumPyと非常に多くの相互運用性があり、Lyftレベル5キットはまた、データの処理を処理するための簡単な方法を提供していますので、心配しないでください。もちろん、その過程でPandas DataFrameを使用する方法もいくつかあるかもしれませんが、ここではLightGBMを用います。\n\ntrain.zarrにはエージェント、エージェント用のマスク、フレーム、シーン、信号機の顔が含まれていますが、これについては後ほど詳しく説明します。"},{"metadata":{},"cell_type":"markdown","source":"リフトのレベル5キットとそれに付属するすべてのものをインポートすることができるようになりました。"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"import l5kit, os\nfrom l5kit.rasterization import build_rasterizer\nfrom l5kit.configs import load_config_data\nfrom l5kit.visualization import draw_trajectory, TARGET_POINTS_COLOR\nfrom l5kit.geometry import transform_points\nfrom tqdm import tqdm\nfrom collections import Counter\nfrom l5kit.data import PERCEPTION_LABELS\nfrom prettytable import PrettyTable\n# データ環境変数を設定する\nos.environ[\"L5KIT_DATA_FOLDER\"] = \"../input/lyft-motion-prediction-autonomous-vehicles\"\n# 取得設定\ncfg = load_config_data(\"../input/lyft-config-files/visualisation_config.yaml\")\nimport plotly.offline as py\npy.init_notebook_mode(connected=True)\nimport plotly.graph_objs as go\nimport plotly.tools as tls","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"では、設定データを見てみましょう。これには、エージェントに関するメタデータ、合計時間、1シーンあたりのフレーム数、シーン時間、フレーム数が含まれます。"},{"metadata":{"trusted":true},"cell_type":"code","source":"from l5kit.data import ChunkedDataset, LocalDataManager\nfrom l5kit.dataset import EgoDataset, AgentDataset\ndm = LocalDataManager()\ndataset_path = dm.require(cfg[\"val_data_loader\"][\"key\"])\nzarr_dataset = ChunkedDataset(dataset_path)\nzarr_dataset.open()\nprint(zarr_dataset)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"しかし現在は、シーンを見て深く分析する時です。理論的には私たちのために重労働をしてくれる気の利いた小さなデータローダを作ることができます。"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"import numpy as np\nfrom IPython.display import display, clear_output\nimport PIL\n \ncfg[\"raster_params\"][\"map_type\"] = \"py_semantic\"\nrast = build_rasterizer(cfg, dm)\ndataset = EgoDataset(cfg, zarr_dataset, rast)\nscene_idx = 2\nindexes = dataset.get_scene_indices(scene_idx)\nimages = []\n\nfor idx in indexes:\n    \n    data = dataset[idx]\n    im = data[\"image\"].transpose(1, 2, 0)\n    im = dataset.rasterizer.to_rgb(im)\n    target_positions_pixels = transform_points(data[\"target_positions\"] + data[\"centroid\"][:2], data[\"world_to_image\"])\n    center_in_pixels = np.asarray(cfg[\"raster_params\"][\"ego_center\"]) * cfg[\"raster_params\"][\"raster_size\"]\n    draw_trajectory(im, target_positions_pixels, data[\"target_yaws\"], TARGET_POINTS_COLOR)\n    clear_output(wait=True)\n    display(PIL.Image.fromarray(im[::-1]))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"というわけで、この一枚の画像にはたくさんの情報が詰まっています。頑張って指摘していきますが、何か間違いがあったら知らせてください。では、画像を分解してみましょう。\n+ ここに4つの道路が交差しています。\n+ 緑のブロブは自動運転車の動きを表していますが、サンプルとしてこのような交通状況での自動運転車の動きを予測する必要があります。"},{"metadata":{},"cell_type":"markdown","source":"このデータの詳細がわからないと、他にどんな推論ができるのかよくわかりませんので、これらの画像を見てみましょう。"},{"metadata":{"trusted":true},"cell_type":"code","source":"import numpy as np\nfrom IPython.display import display, clear_output\nimport PIL\n \ncfg[\"raster_params\"][\"map_type\"] = \"py_satellite\"\nrast = build_rasterizer(cfg, dm)\ndataset = EgoDataset(cfg, zarr_dataset, rast)\nscene_idx = 2\nindexes = dataset.get_scene_indices(scene_idx)\nimages = []\n\nfor idx in indexes:\n    \n    data = dataset[idx]\n    im = data[\"image\"].transpose(1, 2, 0)\n    im = dataset.rasterizer.to_rgb(im)\n    target_positions_pixels = transform_points(data[\"target_positions\"] + data[\"centroid\"][:2], data[\"world_to_image\"])\n    center_in_pixels = np.asarray(cfg[\"raster_params\"][\"ego_center\"]) * cfg[\"raster_params\"][\"raster_size\"]\n    draw_trajectory(im, target_positions_pixels, data[\"target_yaws\"], TARGET_POINTS_COLOR)\n    clear_output(wait=True)\n    display(PIL.Image.fromarray(im[::-1]))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"単純なプロットよりもはるかに詳細な分析を可能にします。私は次のような推論をすると思います。\n+ 緑は自動運転車を表し、青は主に我々が予測する必要がある他のすべての車/車両/外因性因子を表しています。\n+ 私の仮説では、青は車両が通過する必要がある経路を表しています。\n+ 車両が通過する経路を正確に予測できれば、自動運転車がその場で軌道を計算するのが容易になります。"},{"metadata":{},"cell_type":"markdown","source":"また、乗り物の全体的な動きも見てみたいものです。"},{"metadata":{"trusted":true},"cell_type":"code","source":"from IPython.display import display, clear_output\nfrom IPython.display import HTML\n\nimport PIL\nimport matplotlib.pyplot as plt\nfrom matplotlib import animation, rc\ndef animate_solution(images):\n\n    def animate(i):\n        im.set_data(images[i])\n \n    fig, ax = plt.subplots()\n    im = ax.imshow(images[0])\n    \n    return animation.FuncAnimation(fig, animate, frames=len(images), interval=60)\ncfg[\"raster_params\"][\"map_type\"] = \"py_satellite\"\nrast = build_rasterizer(cfg, dm)\ndataset = EgoDataset(cfg, zarr_dataset, rast)\nscene_idx = 34\nindexes = dataset.get_scene_indices(scene_idx)\nimages = []\n\nfor idx in indexes:\n    \n    data = dataset[idx]\n    im = data[\"image\"].transpose(1, 2, 0)\n    im = dataset.rasterizer.to_rgb(im)\n    target_positions_pixels = transform_points(data[\"target_positions\"] + data[\"centroid\"][:2], data[\"world_to_image\"])\n    center_in_pixels = np.asarray(cfg[\"raster_params\"][\"ego_center\"]) * cfg[\"raster_params\"][\"raster_size\"]\n    draw_trajectory(im, target_positions_pixels, data[\"target_yaws\"], TARGET_POINTS_COLOR)\n    clear_output(wait=True)\n    images.append(PIL.Image.fromarray(im[::-1]))\nanim = animate_solution(images)\nHTML(anim.to_jshtml())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"ということで、他の車両の動きと自動運転車の動きのデモです。自動運転車は現在、その動きの中では直線的な道しか取っておらず、直線的な道は他の車両の動きと配置との関係で論理的に見えます。"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"from IPython.display import display, clear_output\nfrom IPython.display import HTML\n\nimport PIL\nimport matplotlib.pyplot as plt\nfrom matplotlib import animation, rc\ndef animate_solution(images):\n\n    def animate(i):\n        im.set_data(images[i])\n \n    fig, ax = plt.subplots()\n    im = ax.imshow(images[0])\n    \n    return animation.FuncAnimation(fig, animate, frames=len(images), interval=60)\ncfg[\"raster_params\"][\"map_type\"] = \"py_semantic\"\nrast = build_rasterizer(cfg, dm)\ndataset = EgoDataset(cfg, zarr_dataset, rast)\nscene_idx = 34\nindexes = dataset.get_scene_indices(scene_idx)\nimages = []\n\nfor idx in indexes:\n    \n    data = dataset[idx]\n    im = data[\"image\"].transpose(1, 2, 0)\n    im = dataset.rasterizer.to_rgb(im)\n    target_positions_pixels = transform_points(data[\"target_positions\"] + data[\"centroid\"][:2], data[\"world_to_image\"])\n    center_in_pixels = np.asarray(cfg[\"raster_params\"][\"ego_center\"]) * cfg[\"raster_params\"][\"raster_size\"]\n    draw_trajectory(im, target_positions_pixels, data[\"target_yaws\"], TARGET_POINTS_COLOR)\n    clear_output(wait=True)\n    images.append(PIL.Image.fromarray(im[::-1]))\nanim = animate_solution(images)\nHTML(anim.to_jshtml())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"また、Lyftのレベル5キットのセマンティックオプションを使うことで、より簡易な動きができるようになりました。"},{"metadata":{"trusted":true},"cell_type":"code","source":"from IPython.display import display, clear_output\nimport PIL\n \ncfg[\"raster_params\"][\"map_type\"] = \"py_semantic\"\nrast = build_rasterizer(cfg, dm)\ndataset = EgoDataset(cfg, zarr_dataset, rast)\nscene_idx = 34\nindexes = dataset.get_scene_indices(scene_idx)\nimages = []\n\nfor idx in indexes:\n    \n    data = dataset[idx]\n    im = data[\"image\"].transpose(1, 2, 0)\n    im = dataset.rasterizer.to_rgb(im)\n    target_positions_pixels = transform_points(data[\"target_positions\"] + data[\"centroid\"][:2], data[\"world_to_image\"])\n    center_in_pixels = np.asarray(cfg[\"raster_params\"][\"ego_center\"]) * cfg[\"raster_params\"][\"raster_size\"]\n    draw_trajectory(im, target_positions_pixels, data[\"target_yaws\"], TARGET_POINTS_COLOR)\n    clear_output(wait=True)\n    images.append(PIL.Image.fromarray(im[::-1]))\n    \nanim = animate_solution(images)\nHTML(anim.to_jshtml())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"あまりクラスタ化されていないビューとしては良いのですが、より詳細で高レベルなデータの概要を知りたい場合は、セマンティックビューを使用してみると良いでしょう。"},{"metadata":{},"cell_type":"markdown","source":"さて、エージェントの観点からはどうでしょうか？これまでのところ、ほとんどの公開ノートブックでは、主にエージェントの視点からモデリングを行っていますので、これを検討するのは非常に興味深いことでしょう。"},{"metadata":{"trusted":true},"cell_type":"code","source":"import numpy as np\nfrom IPython.display import display, clear_output\nimport PIL\n \ncfg[\"raster_params\"][\"map_type\"] = \"py_satellite\"\nrast = build_rasterizer(cfg, dm)\ndataset = AgentDataset(cfg, zarr_dataset, rast)\nscene_idx = 2\nindexes = dataset.get_scene_indices(scene_idx)\nimages = []\n\nfor idx in indexes:\n    \n    data = dataset[idx]\n    im = data[\"image\"].transpose(1, 2, 0)\n    im = dataset.rasterizer.to_rgb(im)\n    target_positions_pixels = transform_points(data[\"target_positions\"] + data[\"centroid\"][:2], data[\"world_to_image\"])\n    center_in_pixels = np.asarray(cfg[\"raster_params\"][\"ego_center\"]) * cfg[\"raster_params\"][\"raster_size\"]\n    draw_trajectory(im, target_positions_pixels, data[\"target_yaws\"], TARGET_POINTS_COLOR)\n    clear_output(wait=True)\n    display(PIL.Image.fromarray(im[::-1]))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"これらをGIFとして保存して、エージェントの動きを可視化した方がいいかもしれません。これをもっとシンプルな形で試してみて、エージェントのデータセットにセマンティックビューを使ってみましょう。"},{"metadata":{"trusted":true},"cell_type":"code","source":"import numpy as np\nfrom IPython.display import display, clear_output\nimport PIL\n \ncfg[\"raster_params\"][\"map_type\"] = \"py_semantic\"\nrast = build_rasterizer(cfg, dm)\ndataset = AgentDataset(cfg, zarr_dataset, rast)\nscene_idx = 2\nindexes = dataset.get_scene_indices(scene_idx)\nimages = []\n\nfor idx in indexes:\n    \n    data = dataset[idx]\n    im = data[\"image\"].transpose(1, 2, 0)\n    im = dataset.rasterizer.to_rgb(im)\n    target_positions_pixels = transform_points(data[\"target_positions\"] + data[\"centroid\"][:2], data[\"world_to_image\"])\n    center_in_pixels = np.asarray(cfg[\"raster_params\"][\"ego_center\"]) * cfg[\"raster_params\"][\"raster_size\"]\n    draw_trajectory(im, target_positions_pixels, data[\"target_yaws\"], TARGET_POINTS_COLOR)\n    clear_output(wait=True)\n    display(PIL.Image.fromarray(im[::-1]))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"また、matplotlib型の視点から全体像を捉えることもできます。 [この素晴らしいノートブックを引用いたします。](https://www.kaggle.com/t3nyks/lyft-working-with-map-api)"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"from l5kit.data.map_api import MapAPI\nfrom l5kit.rasterization.rasterizer_builder import _load_metadata\n\nsemantic_map_filepath = dm.require(cfg[\"raster_params\"][\"semantic_map_key\"])\ndataset_meta = _load_metadata(cfg[\"raster_params\"][\"dataset_meta_key\"], dm)\nworld_to_ecef = np.array(dataset_meta[\"world_to_ecef\"], dtype=np.float64)\n\nmap_api = MapAPI(semantic_map_filepath, world_to_ecef)\nMAP_LAYERS = [\"junction\", \"node\", \"segment\", \"lane\"]\n\n\ndef element_of_type(elem, layer_name):\n    return elem.element.HasField(layer_name)\n\n\ndef get_elements_from_layer(map_api, layer_name):\n    return [elem for elem in map_api.elements if element_of_type(elem, layer_name)]\n\n\nclass MapRenderer:\n    \n    def __init__(self, map_api):\n        self._color_map = dict(drivable_area='#a6cee3',\n                               road_segment='#1f78b4',\n                               road_block='#b2df8a',\n                               lane='#474747')\n        self._map_api = map_api\n    \n    def render_layer(self, layer_name):\n        fig = plt.figure(figsize=(10, 10))\n        ax = fig.add_axes([0, 0, 1, 1])\n        \n    def render_lanes(self):\n        all_lanes = get_elements_from_layer(self._map_api, \"lane\")\n        fig = plt.figure(figsize=(10, 10))\n        ax = fig.add_axes([0, 0, 1, 1])\n        for lane in all_lanes:\n            self.render_lane(ax, lane)\n        return fig, ax\n        \n    def render_lane(self, ax, lane):\n        coords = self._map_api.get_lane_coords(MapAPI.id_as_str(lane.id))\n        self.render_boundary(ax, coords[\"xyz_left\"])\n        self.render_boundary(ax, coords[\"xyz_right\"])\n        \n    def render_boundary(self, ax, boundary):\n        xs = boundary[:, 0]\n        ys = boundary[:, 1] \n        ax.plot(xs, ys, color=self._color_map[\"lane\"], label=\"lane\")\n        \n        \nrenderer = MapRenderer(map_api)\nfig, ax = renderer.render_lanes()","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"def visualize_rgb_image(dataset, index, title=\"\", ax=None):\n    \"\"\"Visualizes Rasterizer's RGB image\"\"\"\n    data = dataset[index]\n    im = data[\"image\"].transpose(1, 2, 0)\n    im = dataset.rasterizer.to_rgb(im)\n\n    if ax is None:\n        fig, ax = plt.subplots()\n    if title:\n        ax.set_title(title)\n    ax.imshow(im[::-1])\n# Prepare all rasterizer and EgoDataset for each rasterizer\nrasterizer_dict = {}\ndataset_dict = {}","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"\n\nrasterizer_type_list = [\"py_satellite\", \"satellite_debug\", \"py_semantic\", \"semantic_debug\", \"box_debug\", \"stub_debug\"]\n\nfor i, key in enumerate(rasterizer_type_list):\n    # print(\"key\", key)\n    cfg[\"raster_params\"][\"map_type\"] = key\n    rasterizer_dict[key] = build_rasterizer(cfg, dm)\n    dataset_dict[key] = EgoDataset(cfg, zarr_dataset, rasterizer_dict[key])\nfig, axes = plt.subplots(2, 3, figsize=(15, 10))\naxes = axes.flatten()\nfor i, key in enumerate([\"stub_debug\", \"satellite_debug\", \"semantic_debug\", \"box_debug\", \"py_satellite\", \"py_semantic\"]):\n    visualize_rgb_image(dataset_dict[key], index=0, title=f\"{key}: {type(rasterizer_dict[key]).__name__}\", ax=axes[i])\nfig.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# メタデータの探索"},{"metadata":{},"cell_type":"markdown","source":"画像を探索することができるようになったので、ZARRファイルについても少し詳しく調べてみましょう。Pythonライブラリを使って探索するのはかなり簡単で、特にNumPyとの相互運用性があるという点では、とても便利です。"},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"scenes\", zarr_dataset.scenes)\nprint(\"scenes[0]\", zarr_dataset.scenes[0])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"また、ChunkedDatasetを使ってシーンのCSVファイルを生成することもできます。"},{"metadata":{"trusted":true},"cell_type":"code","source":"import pandas as pd\nscenes = zarr_dataset.scenes\nscenes_df = pd.DataFrame(scenes)\nscenes_df.columns = [\"data\"]; features = ['frame_index_interval', 'host', 'start_time', 'end_time']\nfor i, feature in enumerate(features):\n    scenes_df[feature] = scenes_df['data'].apply(lambda x: x[i])\nscenes_df.drop(columns=[\"data\"],inplace=True)\nprint(f\"scenes dataset: {scenes_df.shape}\")\nscenes_df.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"しかし、私たちはこれで十分なのでしょうか？いいえ、そうではありません。今後はKkkillerのデータセットを使って、さらに表形式のデータを探っていこうと思います。"},{"metadata":{"trusted":true},"cell_type":"code","source":"agents = pd.read_csv('../input/lyft-motion-prediction-autonomous-vehicles-as-csv/agents_0_10019001_10019001.csv')\nagents","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"ここには、以下のようなおなじみの機能を含む、私たちのために使用できる豊富な情報があります。\n1. x, y, および z の共線性\n2. 偏走\n3. その他の外部要因の確率"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"import seaborn as sns\ncolormap = plt.cm.magma\ncont_feats = [\"centroid_x\", \"centroid_y\", \"extent_x\", \"extent_y\", \"extent_z\", \"yaw\"]\nplt.figure(figsize=(16,12));\nplt.title('Pearson correlation of features', y=1.05, size=15);\nsns.heatmap(agents[cont_feats].corr(),linewidths=0.1,vmax=1.0, square=True, \n            cmap=colormap, linecolor='white', annot=True);\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"ここでは、 **centroid_x** と **centroid_y** という変数には強い負の相関があり、最も強い相関は **extent_z** と **extent_x** の間のもので、0.4 となっています。また、この問題の代替的なアプローチとして、kkiller氏が彼の素晴らしいカーネルで実証したように、XGBoost/LightGBMモデルを使ってみることもできます。"},{"metadata":{},"cell_type":"markdown","source":"### centroid_x と centroid_y"},{"metadata":{"trusted":true},"cell_type":"code","source":"import seaborn as sns\nplot = sns.jointplot(x=agents['centroid_x'][:1000], y=agents['centroid_y'][:1000], kind='hexbin', color='blueviolet')\nplot.set_axis_labels('center_x', 'center_y', fontsize=16)\n\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"2つのセントロイドがやや強い負の相関と、一見似たような変数分布を持っているように見えます。両方の変数の間に負の相関があるようです。"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"fig = plt.figure(figsize=(15, 15));\nsns.distplot(agents['centroid_x'], color='steelblue');\nsns.distplot(agents['centroid_y'], color='purple');\nplt.title(\"Distributions of Centroid X and Y\");","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"centroid_xの右に歪んだ分布は、 centroid_yのそれよりもかなり極端なようです。どちらの分布も非常に似ていません。"},{"metadata":{},"cell_type":"markdown","source":"### extent_x, extent_y と extent_z"},{"metadata":{"trusted":true},"cell_type":"code","source":"fig = plt.figure(figsize=(15, 15));\nsns.distplot(agents['extent_x'], color='steelblue');\nsns.distplot(agents['extent_y'], color='purple');\n\nplt.title(\"Distributions of Extents X and Y\");","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"エクステントXとエクステントYの分布は、セントロイドXと同様に大きく右に傾いているように見えますが、プロットの読みやすさのためにエクステントZを省いていますので、それを見てみましょう。\n\nデータを滑らかにします。"},{"metadata":{"trusted":true},"cell_type":"code","source":"fig = plt.figure(figsize=(15, 15));\nsns.distplot(agents['extent_z'], color='steelblue');\n\nplt.title(\"Distributions of Extents z\");","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"もう一度言いますが、すべての `extent` 変数と同じように、右に歪んだ分布を持っています。"},{"metadata":{},"cell_type":"markdown","source":"### 偏走"},{"metadata":{"trusted":true},"cell_type":"code","source":"fig = plt.figure(figsize=(15, 15));\nsns.distplot(agents['yaw'], color='steelblue');\n\nplt.title(\"Distributions of Extents z\");","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"この分布は、私がそれらを呼ぶように、いくつかの \"突起 \"を持っているように見えます。これで、我々の目的がどれだけ実現可能かを確認するために、フレームデータの探索に移ることができるようになりました。"},{"metadata":{"trusted":true},"cell_type":"code","source":"frms = pd.read_csv(\"../input/lyft-motion-prediction-autonomous-vehicles-as-csv/frames_0_124167_124167.csv\")\nfrms.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"ここには、セントロイドに関する回転がありますが、これは非常に興味深い考察になるでしょう。これらの変数を一度に複数チェックする必要がありそうです。"},{"metadata":{},"cell_type":"markdown","source":"### 自己回転"},{"metadata":{},"cell_type":"markdown","source":"まず第一に、それぞれに対応する9つの自己回転列があります。そこで、より高度な分析に移る前に、これらの変数の相関関係を簡単にチェックしたいと思います。"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"import seaborn as sns\ncolormap = plt.cm.magma\ncont_feats = [\"ego_rotation_xx\", \"ego_rotation_xy\", \"ego_rotation_xz\", \"ego_rotation_yx\", \"ego_rotation_yy\", \"ego_rotation_yz\", \"ego_rotation_zx\", \"ego_rotation_zy\", \"ego_rotation_zz\"]\nplt.figure(figsize=(16,12));\nplt.title('Pearson correlation of features', y=1.05, size=15);\nsns.heatmap(frms[cont_feats].corr(),linewidths=0.1,vmax=1.0, square=True, \n            cmap=colormap, linecolor='white', annot=True);\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"この相関分析から注意すべきこと\n1. y` と `z` の回転座標はほとんどの場合、相関がないように見える。\n2. `x` を持つ座標は z 次元の回転と強く相関している (これは何かを示しているのだろうか？)"},{"metadata":{},"cell_type":"markdown","source":"### 二値特徴"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"import numpy as np\nzero_count_list, one_count_list = [], []\ncols_list = [\"label_probabilities_PERCEPTION_LABEL_UNKNOWN\",\"label_probabilities_PERCEPTION_LABEL_CAR\",\"label_probabilities_PERCEPTION_LABEL_CYCLIST\",\"label_probabilities_PERCEPTION_LABEL_PEDESTRIAN\"]\nfor col in cols_list:\n    zero_count_list.append((agents[col]==0).sum())\n    one_count_list.append((agents[col]==1).sum())\n\nN = len(cols_list)\nind = np.arange(N)\nwidth = 0.35\n\nplt.figure(figsize=(6,10))\np1 = plt.barh(ind, zero_count_list, width, color='purple')\np2 = plt.barh(ind, one_count_list, width, left=zero_count_list, color=\"steelblue\")\nplt.yticks(ind, cols_list)\nplt.legend((p1[0], p2[0]), ('Zero count', 'One Count'))\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"d3.jsを使ったバイナリ機能のクイックチェック - グラフィックのレンダリングに時間がかかるかもしれません。"},{"metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"cell_type":"code","source":"\"\"\"\"\"\"\nimport json, random\ndef parse_demo(col):\n    bigtxt = \";\".join(df[col].dropna())\n    wrds = bigtxt.split(\";\")\n    wrds = Counter(wrds).most_common()\n    return wrds \n\nstrr = \"id,value,color\\nAudience Demographics,\\n\"\ndemographics = ['Gender', 'Age', 'SexualOrientation', 'RaceEthnicity', 'EducationParents', 'Dependents']\n#demographics = ['Gender', 'Age', 'SexualOrientation', 'RaceEthnicity', 'EducationParents']\ncolors = ['#5b9aff', '#ff77bd', '#82ff8a', '#9b9493', '#5b9aff', '#ff77bd', '#82ff8a', '#9b9493']\nfor i,col in enumerate(demographics):\n    strr += \"Audience Demographics.\" + col + \",\\n\"\n    \n    response = parse_demo(col)\n    total = sum([x[1] for x in response])\n    for term in response:\n        cent = float(term[1])*100 / total\n        strr += \"Audience Demographics.\" + col +\".\"+ term[0].split(\"(\")[0].replace(\",\",\"\") +\",\"+ str(cent) + \",\"+colors[i]+\"\\n\"\n\nfout = open(\"tomdata.csv\", \"w\")\n\nfout.write(strr)\n\n\n\nhtml2 =\"\"\" <style>\n.link {\n        fill: none;\n        stroke: #555;\n        stroke-opacity: 0.4;\n        stroke-width: 1px;\n    }\n    text {\n        font-family: \"Arial Black\", Gadget, sans-serif;\n        fill: black;\n        font-weight: bold;\n        font-size: 14px\n    }\n\n    .xAxis .tick text{\n        fill: black;\n    }\n    \n    .grid .tick line{\n        stroke: grey;\n        stroke-dasharray: 5, 10;\n        opacity: 0.7;\n    }\n    .grid path{\n        stroke-width: 0;\n    }\n\n    .node1 circle {\n        fill: #999;\n    }\n    .node1--internal circle {\n        fill: #555;\n    }\n    .node1--internal text {\n        font-size: 16px;\n        text-shadow: 0 2px 0 #fff, 0 -2px 0 #fff, 2px 0 0 #fff, -2px 0 0 #fff;\n    }\n    .node1--leaf text {\n        fill: white;\n    }\n    .ballG text {\n        fill: white;\n    }\n\n    .shadow {\n        -webkit-filter: drop-shadow( -1.5px -1.5px 1.5px #000 );\n        filter: drop-shadow( -1.5px -1.5px 1.5px #000 );\n    }</style>\n    <body>\n    <br><br>\n    <svg id=\"five\" width=\"900\" height=\"1200\"></svg>\n    <br><br><br>\n</body>\n\"\"\"\n\n\njs2 = \"\"\"\n \n require([\"d3\"], function(d3) {\n  \n    var svg1 = d3.select(\"#five\"),\n            width = +svg1.attr(\"width\"),\n            height = +svg1.attr(\"height\"),\n            g1 = svg1.append(\"g\").attr(\"transform\", \"translate(20,10)\");       // move right 20px.\n            \n    var xScale =  d3.scaleLinear()\n            .domain([0,100])\n            .range([0, 400]);\n\n    var xAxis = d3.axisTop()\n            .scale(xScale);\n\n    // Setting up a way to handle the data\n    var tree1 = d3.cluster()                 // This D3 API method setup the Dendrogram datum position.\n            .size([height, width - 550])    // Total width - bar chart width = Dendrogram chart width\n            .separation(function separate(a, b) {\n                return a.parent == b.parent            // 2 levels tree1 grouping for category\n                || a.parent.parent == b.parent\n                || a.parent == b.parent.parent ? 0.4 : 0.8;\n            });\n\n    var stratify = d3.stratify()            // This D3 API method gives cvs file flat data array dimensions.\n            .parentId(function(d) { return d.id.substring(0, d.id.lastIndexOf(\".\")); });","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# ベースライン・モデル (ソース: [こちら](https://github.com/lyft/l5kit/blob/master/examples/agent_motion_prediction/agent_motion_prediction.ipynb) と [こちら](https://www.kaggle.com/pestipeti/pytorch-baseline-inference))"},{"metadata":{},"cell_type":"markdown","source":"これは主に私がLyftのベースラインモデルを使って、提供されたデータセットフォーマットでPyTorchモデルにどのようにフィットするかを実演するため、トレーニングしているものです。\n\nまた、PyTorch Lightningとそれに付随するすべての利点を使用しています。PL-Lightningについては、後で詳しく説明します。"},{"metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"cell_type":"code","source":"from typing import Dict\n!pip install pytorch-lightning\n\nfrom tempfile import gettempdir\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport torch\nfrom torch import nn, optim\nfrom torch.utils.data import DataLoader\nfrom torchvision.models.resnet import resnet18\nfrom tqdm import tqdm\nfrom l5kit.configs import load_config_data\nfrom l5kit.data import LocalDataManager, ChunkedDataset\nfrom l5kit.dataset import AgentDataset, EgoDataset\nfrom l5kit.rasterization import build_rasterizer\nfrom l5kit.evaluation import write_pred_csv, compute_metrics_csv, read_gt_csv, create_chopped_dataset\nfrom l5kit.evaluation.chop_dataset import MIN_FUTURE_STEPS\nfrom l5kit.evaluation.metrics import neg_multi_log_likelihood, time_displace\nfrom l5kit.geometry import transform_points\nfrom l5kit.visualization import PREDICTED_POINTS_COLOR, TARGET_POINTS_COLOR, draw_trajectory\nfrom prettytable import PrettyTable\nfrom pathlib import Path\nimport pytorch_lightning as pl\nimport os\ncfg = load_config_data('../input/lyft-config-files/agent_motion_config.yaml')\nclass Mod(torch.nn.Module):\n    def __init__(self, cfg: Dict):\n        super(Mod, self).__init__()\n        self.backbone = resnet18(pretrained=False)\n        \n        num_history_channels = (cfg[\"model_params\"][\"history_num_frames\"] + 1) * 2\n        num_in_channels = 3 + num_history_channels\n\n        self.backbone.conv1 = nn.Conv2d(\n            num_in_channels,\n            self.backbone.conv1.out_channels,\n            kernel_size=self.backbone.conv1.kernel_size,\n            stride=self.backbone.conv1.stride,\n            padding=self.backbone.conv1.padding,\n            bias=False,\n        )\n        \n        # This is 512 for resnet18 and resnet34;\n        # And it is 2048 for the other resnets\n        backbone_out_features = 512\n\n        # X, Y coords for the future positions (output shape: Bx50x2)\n        num_targets = 2 * cfg[\"model_params\"][\"future_num_frames\"]\n\n        # You can add more layers here.\n        self.head = nn.Sequential(\n            # nn.Dropout(0.2),\n            nn.Linear(in_features=backbone_out_features, out_features=4096),\n        )\n\n        self.logit = nn.Linear(4096, out_features=num_targets)\n    def forward(self):\n        x = self.backbone.conv1(x)\n        x = self.backbone.bn1(x)\n        x = self.backbone.relu(x)\n        x = self.backbone.maxpool(x)\n\n        x = self.backbone.layer1(x)\n        x = self.backbone.layer2(x)\n        x = self.backbone.layer3(x)\n        x = self.backbone.layer4(x)\n\n        x = self.backbone.avgpool(x)\n        x = torch.flatten(x, 1)\n        \n        x = self.head(x)\n        x = self.logit(x)\n        \n        return x        \n\ndef forward(data, model, device, criterion):\n    inputs = data[\"image\"].to(device)\n    target_availabilities = data[\"target_availabilities\"].unsqueeze(-1).to(device)\n    targets = data[\"target_positions\"].to(device)\n    # Forward pass\n    outputs = model(inputs).reshape(targets.shape)\n    loss = criterion(outputs, targets)\n    # not all the output steps are valid, but we can filter them out from the loss using availabilities\n    loss = loss * target_availabilities\n    loss = loss.mean()\n    return loss, outputs\n\nclass LightningLyft(pl.LightningModule):\n    def __init__(self, model):\n        super(LightningLyft, self).__init__()\n        self.model = model\n        \n    def forward(self, x, *args, **kwargs):\n        return self.model(x)\n    \n    def prepare_train_data(self):\n        train_cfg = cfg[\"train_data_loader\"]\n        rasterizer = build_rasterizer(cfg, dm)\n        train_zarr = ChunkedDataset(dm.require(train_cfg[\"key\"])).open()\n        train_dataset = AgentDataset(cfg, train_zarr, rasterizer)\n        train_dataloader = DataLoader(train_dataset, shuffle=train_cfg[\"shuffle\"], batch_size=train_cfg[\"batch_size\"], \n                             num_workers=train_cfg[\"num_workers\"])\n        return train_dataloader\n            \n    def training_step(self, batch, batch_idx):\n        tr_it = iter(train_dataloader)\n        progress_bar = tqdm(range(cfg[\"train_params\"][\"max_num_steps\"]))\n        losses_train = []\n        model = self.model\n        for n in [0, 1, 2 , 3, 4]:\n            try:\n                data = next(tr_it)\n            except StopIteration:\n                tr_it = iter(train_dataloader)\n                data = next(tr_it)\n            model.train()\n            torch.set_grad_enabled(True)\n            device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n            optimizer = optim.Adam(model.parameters(), lr=1e-3)\n            criterion = nn.MSELoss(reduction=\"none\")\n            loss, _ = forward(data, model, device, criterion)\n\n            # Backward pass\n            optimizer.zero_grad()\n            loss.backward()\n            optimizer.step()\n\n            losses_train.append(loss.item())\n            print(f\"LOSS FOR EPOCH {n}: {loss.item()}\")\n            \n    def configure_optimizers(self):\n        optimizer = optim.Adam(model.parameters(), lr=1e-3)\n        return optimizer","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# ===== INIT DATASET\ntrain_cfg = cfg[\"train_data_loader\"]\nrasterizer = build_rasterizer(cfg, dm)\ntrain_zarr = ChunkedDataset(dm.require(train_cfg[\"key\"])).open()\ntrain_dataset = AgentDataset(cfg, train_zarr, rasterizer)\ntrain_dataloader = DataLoader(train_dataset, shuffle=train_cfg[\"shuffle\"], batch_size=train_cfg[\"batch_size\"], \n                             num_workers=train_cfg[\"num_workers\"])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\nmodel = Mod(cfg).to(device)\noptimizer = optim.Adam(model.parameters(), lr=1e-3)\ncriterion = nn.MSELoss(reduction=\"none\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# ==== TRAIN LOOP\nres = []\ntr_it = iter(train_dataloader)\nmodel = LightningLyft(build_model(cfg))\nprogress_bar = tqdm(range(cfg[\"train_params\"][\"max_num_steps\"]))\nlosses_train = []\nfor _ in progress_bar:\n    try:\n        data = next(tr_it)\n    except StopIteration:\n        tr_it = iter(train_dataloader)\n        data = next(tr_it)\n    model.train()\n    torch.set_grad_enabled(True)\n    loss, _ = forward(data, model, device, criterion)\n    res.append(_)\n    # Backward pass\n    optimizer.zero_grad()\n    loss.backward()\n    optimizer.step()\n\n    losses_train.append(loss.item())\n    progress_bar.set_description(f\"loss: {loss.item()} loss(avg): {np.mean(losses_train)}\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"PyTorch lightningを使ったモデルの学習は初めてなので、かなり満足しています。しかし今は、このモデルが具体的に何を学習したのかを見てみたいと思います。<br>予測値を結果用の配列 `res` に保存することができました。学習したことを確認するのは後になりますが、今後は予測を進めていきます。"},{"metadata":{},"cell_type":"markdown","source":"ソース: https://github.com/lyft/l5kit/blob/master/examples/visualisation/visualise_data.ipynb"}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}