LoginSignup
6
2

More than 1 year has passed since last update.

深掘りNxシリーズ ~ tensor を知る ③ 算術計算その2 行列の積 ~

Last updated at Posted at 2023-01-05

東京にいるけどfukuokaexのYOSUKEです。
最近、エリクサーちゃんで学ぶ Elixirの動画を作成し始めてるので良かったらチャンネル登録お願いします。

さて、兼ねてより興味があったライブラリ、Nxについて勉強して行こうと思います。この記事は自分の為の備忘録でもあります。が、Elixir初学者でも分かりやすいように、なるべく解説をつけながらアウトプット目指します。

前回までの記事はこちら

深掘りNxシリーズ
|> 深掘りNxシリーズ ~ tensor を知る ① ~
|> 深掘りNxシリーズ ~ tensor を知る ② 算術計算 ~

同時進行で以下も学習しています。
ゼロから作る Deep LearningをElixirで学ぶシリーズ
|> ~ Numpy -> Nx に置き換えて 1章やる~
|> ~ Perceptron(パーセプトロンの実装) ~
|> ~ 3章 Neural Network : NN を学ぶ (前編)~

で、3章をやっているところで、前回、行列同士の積算がどうも違う結果になった。という所で止まっていましたが、これの解が見つかりました。という事で早速見て行きます。

行列の積

結論から言うと、行列の積の計算はNx.dotを使います。

詳しくは、前回も触れているのでここではNxの行列の積の計算をする関数があったのでそちらを紹介します。

iex()> a = Nx.tensor([[1,2],[3,4]])
#Nx.Tensor<
  s64[2][2]
  [
    [1, 2],
    [3, 4]
  ]
>
iex()> b = Nx.tensor([[5,6],[7,8]])
#Nx.Tensor<
  s64[2][2]
  [
    [5, 6],
    [7, 8]
  ]
>
iex()> Nx.dot(a, b)
#Nx.Tensor<
  s64[2][2]
  [
    [19, 22],
    [43, 50]
  ]
>

行列の形が違う同士でもあるルールを守れば計算できます。

iex()> a = Nx.tensor([[1,2],[3,4],[5,6]])
#Nx.Tensor<
  s64[3][2]
  [
    [1, 2],
    [3, 4],
    [5, 6]
  ]
>
iex()> b = Nx.tensor([[1,2,3],[4,5,6]])
#Nx.Tensor<
  s64[2][3]
  [
    [1, 2, 3],
    [4, 5, 6]
  ]
>
iex()> c = Nx.dot(a, b)
#Nx.Tensor<
  s64[3][3]
  [
    [9, 12, 15],
    [19, 26, 33],
    [29, 40, 51]
  ]
>

あるルールを守らないとerrorが出ます。

iex()> Nx.dot(a, c)
** (ArgumentError) dot/zip expects shapes to be compatible, dimension 1 of left-side (2) does not equal dimension 0 of right-side (3)
    (nx 0.4.1) lib/nx/shape.ex:495: Nx.Shape.validate_zip_reduce_axes!/4
    (nx 0.4.1) lib/nx/shape.ex:470: Nx.Shape.zip_reduce/6
    (nx 0.4.1) lib/nx/shape.ex:1616: Nx.Shape.dot/8
    (nx 0.4.1) lib/nx.ex:9392: Nx.dot/6

気を付けるべきルールは Nx.shape で確認できます。

iex()> Nx.shape a
{3, 2}
iex()> Nx.shape b
{2, 3}
iex()> Nx.shape c
{3, 3}

このタプルで帰ってきた{3, 2}{2, 3}を見ると内側の数字が同じです。
この場合は計算ができます。これが、{3, 2}{3, 3}これだとエラーになります。

この事からも分かる通り、行列の積は a x b と b x a で結果が変わります。

実際にいくつかパターンを見て行きましょう。

iex()> Nx.dot(b, a)
#Nx.Tensor<
  s64[2][2]
  [
    [22, 28],
    [49, 64]
  ]
>
iex()> Nx.dot(a, b)
#Nx.Tensor<
  s64[3][3]
  [
    [9, 12, 15],
    [19, 26, 33],
    [29, 40, 51]
  ]
>
iex()> Nx.dot(b, c)
#Nx.Tensor<
  s64[2][3]
  [
    [134, 184, 234],
    [305, 418, 531]
  ]
>
iex()> Nx.dot(c, b)
** (ArgumentError) dot/zip expects shapes to be compatible, dimension 1 of left-side (3) does not equal dimension 0 of right-side (2)
    (nx 0.4.1) lib/nx/shape.ex:495: Nx.Shape.validate_zip_reduce_axes!/4
    (nx 0.4.1) lib/nx/shape.ex:470: Nx.Shape.zip_reduce/6
    (nx 0.4.1) lib/nx/shape.ex:1616: Nx.Shape.dot/8
    (nx 0.4.1) lib/nx.ex:9392: Nx.dot/6
iex()> Nx.dot(c, a)
#Nx.Tensor<
  s64[3][2]
  [
    [120, 156],
    [262, 340],
    [404, 524]
  ]
>

という事で、一番知りたかった、行列の積の計算について、今回わかりました。

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2