AI & 機械学習

機械学習はアスリートの技能を高められるか

※この投稿は米国時間 2021 年 2 月 5 日に、Google Cloud blog に投稿されたものの抄訳です。


Super Bowl(スーパーボウル)、いえ、異名の Superb Owl(すごいフクロウ)と呼ぶ方が好きなのですが、非常にアメリカらしい日曜日のことで、際限なく食べ続けるナチョスや高額コマーシャルはよく知られており、これであと 5 年は頑張れるエネルギーをもらえます

冴えない数学オタクとしては、これまでスーパーボウルの「フットボール」の部分に多く関わってきたとは言えません。それはさておき、スポーツ、データ分析、機械学習が集まれば強力なトリオが生まれます。ほとんどのプロチームはこのテクノロジーをさまざまな方法で活用しています。それは、選手の動きのトラッキングから、怪我の発見や選手の背番号の読み取りまで応用されています。運動があまり得意ではない者にとっては、機械学習はむしろ自分たちの運動能力の向上に使える可能性があります。

これが今日試してみることです。この投稿では、スポーツを 1 つ選び、そのパフォーマンスを機械学習で分析する方法をご紹介します(例では私のテニスのサーブを使っていますが、この手法は他のスポーツにも簡単に応用できます)。Video Intelligence API を使用してフォームをトラッキングし、AutoML Vision を使用してテニスボールをトラッキングし、数学を利用してすべてを Python にまとめます。

ご自身でこのプロジェクトをお試しになる場合は、Qwiklab をご参照ください。

このアイデアを教えてくれた Google の同僚 Zack Akil に感謝します。彼は同じ手法でサッカー(失礼、「フットボール」と呼ぶべきでした)のペナルティ キックを分析しました。

機械学習を使用してテニスのサーブを分析する

まず、自分のテニスサーブの動画データを集めることから始めました。テニスコートに行き、三脚を使って動画を撮影しました。次に、そのクリップを知り合いのテニスコーチに送ると、次のようなフィードバックが返ってきました。

2
3

これらの図では、プロの選手のサーブと違っている重要な部分がうまく分析されていました。私はこれを使って、機械学習アプリで分析する内容を決めることにしました。

  1. サーブをするときに膝は曲がっていたか

  2. ボールを打つときに肘は伸びていたか

  3. 打ったボールの実際の速度はどうだったか(これは個人的な興味でした)

姿勢検出でフォームを分析する

膝と肘の角度を計算するために、姿勢検出を利用することにしました。これは機械学習の手法の一つで、人の写真や動画を分析して、身体部位の位置を特定します。姿勢検出に使用できるツールはたくさんありますが(TensorFlow.js など)、このプロジェクトでは Google Cloud Video Intelligence API の新しい人感センサー機能を試すことにしました(この API は聞き覚えがあると思います。AI を活用した動画アーカイブの作成方法で、家族の動画の中の物体、文字、発話の分析に使用した API です)。人感センサー機能は、さまざまな身体部位、顔の特徴、衣服を認識します。ドキュメントからの抜粋をご覧ください。

unnamed_4

まず、テニスのサーブの動画からサーブを打っているセクションだけを切り取りました。撮影したサーブは 17 球だけだったので、この処理はすぐにできました。次に、動画を Google Cloud Storage にアップロードし、Video Intelligence API を使用して分析しました。コードは次のようになります。

  def detect_person(input_uri, output_uri):
    """Detects people in a video."""

    client = videointelligence.VideoIntelligenceServiceClient(credentials=service_account.Credentials.from_service_account_file(
    './key.json'))

    # Configure the request
    config = videointelligence.types.PersonDetectionConfig(
        include_bounding_boxes=True,
        include_attributes=True,
        include_pose_landmarks=True,
    )
    context = videointelligence.types.VideoContext(person_detection_config=config)

    # Start the asynchronous request
    operation = client.annotate_video(
        input_uri=input_uri,
        output_uri=output_uri,
        features=[videointelligence.enums.Feature.PERSON_DETECTION],
        video_context=context,
    )

    return operation

この API を呼び出すには、Cloud Storage 内の動画の保存先と、Video Intelligence API が結果を書き込む Cloud Storage 内の出力先を渡す必要があります。

Video Intelligence API による動画分析が完了したところで、その結果を可視化しました。それには、@wbobeirne によって作成されたこちらの便利なツールを使用しました。次のようなわかりやすく可視化された動画が出力されました。

1

姿勢検出は、機械学習モデルをトレーニングする際の事前処理ステップとして優れています。たとえば、API の出力(関節の位置の経時的変化)を、サーブを打とうとしているかどうかやサーブがネットを越えるかどうかなどを予測する 2 つ目の機械学習モデルの入力特徴量として使用できます。ここでは、もっとシンプルにして、高校の数学でサーブを分析してみました。

最初に、左右の手首の位置を y 軸として経時的変化をグラフにしました。

unnamed_5

乱雑に見えるかもしれませんが、データはサーブの初めから終わりまでを実に明確に示しています。青い折れ線は左手首の位置を表していて、ボールをトスした瞬間が頂点になっています。この数秒後が右手首(オレンジ色の折れ線)の頂点となっていて、ラケットでボールを打つ瞬間です。

このデータを使用すると、ボールをトスした時点と打った時点を正確に確認できます。このデータを、ボールを打つときの肘の角度と照合してみます。これを行うには、Video Intelligence API の出力(未加工のピクセル位置)を角度に変換する必要があります。

変換はどのようにすればよいでしょうか。言うまでもなく、余弦の法則を使います(冗談です。この法則はすっかり忘れていて、調べ直す必要がありました。こちらに余弦の法則と Python コードのわかりやすい説明があります)。

余弦の法則は空間の点を角度に変換するときの重要な要素です。コードは次のようになります。

  class Point:
  def __init__(self, x, y):
    self.x = x
    self.y = y 
    
def getAngle(a, b, c):
    ang = math.degrees(math.atan2(c.y-b.y, c.x-b.x) - math.atan2(a.y-b.y, a.x-b.x))
    return ang
    
  def computeElbowAngle(row, which='right'):
  wrist = Point(row[f'{which}_wrist_x'], row[f'{which}_wrist_y'])
  elbow = Point(row[f'{which}_elbow_x'], row[f'{which}_elbow_y'])
  shoulder = Point(row[f'{which}_shoulder_x'], row[f'{which}_shoulder_y'])
  return getAngle(wrist, elbow, shoulder)

def computeShoulderAngle(row, which='right'):
  elbow = Point(row[f'{which}_elbow_x'], row[f'{which}_elbow_y'])
  shoulder = Point(row[f'{which}_shoulder_x'], row[f'{which}_shoulder_y'])
  hip = Point(row[f'{which}_hip_x'], row[f'{which}_hip_y'])
  return getAngle(hip, shoulder, elbow)

def computeKneeAngle(row, which='right'):
  hip = Point(row[f'{which}_hip_x'], row[f'{which}_hip_y'])
  knee = Point(row[f'{which}_knee_x'], row[f'{which}_knee_y'])
  ankle = Point(row[f'{which}_ankle_x'], row[f'{which}_ankle_y'])
  return getAngle(ankle, knee, hip)

これらの式を使って、肘の角度の経時的変化をグラフにしました。

unnamed_6

手首の位置の高さと肘の角度を照合して、私の肘の角度は約 120 度ということがわかりました(まっすぐではありませんでした)。フォームを指摘してくれるテニスコーチが知り合いにいなかったとしても、肘の角度がプロとは異なっている点を見つけて教えてくれるアプリがあったらいいですよね。

次に同じ式を使って膝と肩の角度も計算しました(詳細については、コードをご覧ください)。

サーブの速度を計算する

姿勢検出を使って身体部位の角度を計算できましたが、ラケットで打った後のボールの速度も計算したいと考えました。これを行うには、小さくて速いテニスボールの経時的な動きをトラッキングできる必要がありました。

unnamed_7

ご覧のように、テニスボールは遠くにあって不鮮明なので、識別が難しいです。

これには、Zack が Football Pier プロジェクトで行っていたのと同じ方法、つまりカスタムの AutoML Vision モデルをトレーニングすることで対処しました。

AutoML Vision をご存じではない方のために説明しますと、これは、コードを記述せずにディープ ニューラル ネットワークを使用してコンピュータ ビジョンモデルを構築する方法です。AutoML Vision の一番の利点は、ML について何も知らなくても ML を使用できることです。

AutoML Vision を使用すると、独自のラベル付きデータ(つまりラベル付きのテニスボール)をアップロードすれば、モデルのトレーニングが自動的に行われます。

AutoML Vision を使用してオブジェクト検出モデルをトレーニングする

まず、サーブの動画から 30 秒のクリップを作成し、ビジョンモデルのトレーニング データとして使えるようにそのクリップを個々の画像に分割しました。

  ffmpeg -i filename.mp4 -vf fps=10 -ss 00:00:01 -t 00:00:30 tmp/snapshots/%03d.jpg

このコマンドは、私が提供しているノートブックから実行することも、ffmpeg がインストールされている場合はコマンドラインから実行することもできます。このコマンドは mp4 を受け取って、jpg 形式のスナップショットをたくさん作成します(ここでは fps=20、つまり 1 秒あたり 20 フレームです)。-ss フラグは、動画のどこからスナップショットを開始するか(ここでは 1 秒目から開始)を制御し、-t フラグは対象にする秒数(ここでは 30)を制御します。

すべてのスナップショットが作成されたら、次のコマンドを使って Google Cloud Storage にスナップショットをアップロードします。

  gsutil mb gs://my_neat_bucket  # create a new bucket

gsutil cp tmp/snapshots/* gs://my_neat_bucket/snapshots

次に、Google Cloud Console に移動して、左側のメニューから [Vision] を選択します。

unnamed_8

AutoML Vision モデルを新規作成して、画像をインポートします。

unnamed_9

簡単な復習: 機械学習の分類器とは何でしょうか。これは、例からラベル付けの方法を学習するモデルタイプです。そのため、この独自の AutoML Vision モデルをトレーニングするには、モデルの学習元となるラベル付けされたトレーニング データを用意する必要があります。

データがアップロードされると、AutoML Vision の [イメージ] タブに表示されます。

unnamed_10

ここで、ラベルの適用を開始できます。1 つの画像をクリックします。以下のような編集ビューで、クリックして小さい境界ボックスをドラッグします。

unnamed_1

このモデルでは、約 300 個の画像に手動でラベルを付けましたが、30 分ほどかかりました。データのラベル付けが完了したら、1 回クリックするだけで AutoML がモデルのトレーニングを始めます。[新しいモデルをトレーニング] ボタンをクリックして待つだけです。

unnamed_11

モデルのトレーニングが完了したら、次のような [評価] タブでモデルの品質を評価できます。

unnamed_12

ご覧のように、このモデルはきわめて正確で、精度も再現率も約 96% です。

この精度は画像でボールの位置をトラッキングする、つまり速度を計算するのに十分すぎるほど高いです。

unnamed_2

モデルのトレーニングが完了したら、こちらの Jupyter Notebook のコードを使用して、上に示したようなちょっとした動画を作成できます。

この動画を使用して、ボールの位置の経時的変化をグラフにして、速度を計算できます。

unnamed_13

気付くのが遅すぎたのですが、残念なことに致命的なミスを犯してしまいました。速度とは、距離の経時的変化ですよね。ところが、プレーヤーの自分からカメラまでの距離を確認しなかったので、距離をマイルやメートルで計算できず、ピクセル数でしか計算できませんでした。私は 1 秒あたり約 200 ピクセルの速さのサーブを打っていることがわかりました。よくできました。

これで、いくつかの手法を使って独自のスポーツ向け機械学習トレーナー アプリを構築できることがわかりました。ご自身でスポーツ アナライザを作成する場合は、ぜひお知らせください

-AI 応用エンジニア Dale Markowitz