質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.10%

○○ = self(x) を教えてください。

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 108

beggier1

score 2

https://github.com/YutaroOgawa/Deep-Reinforcement-Learning-Book/blob/master/program/6_5_A2C_Advanced_ActorCritic.ipynb

上記のコードで強化学習を学習しております。
5つ目のセルを以下に抜粋します。

質問1
foward が5つ目のセル以外で使われているところを発見できないのですが、どこで使用しているのでしょうか?
この関数においてニューラルネットワークに学習データを与え、出力していると考えているのですが...
無いのであればなぜこの関数は書かれていて、他のどこでニューラルネットワークに学習データを与えているのでしょうか?

質問2
act関数の中に
value, actor_output = self(x)
が見られるのですが、self(x)とは何ですか?
selfはインスタンス自身という認識で今までこのような使い方をしたことがなく疑問を持っています。
推測としては
ニューラルネットワークに学習データを与え、出てきた出力をvalue, actor_outputに格納していると考えています。
するとself(x)はforward関数を表すのでしょうか?

質問3
また、以下に質問2に対する自分の理解の為に作成したコードとエラー文を載せておきます。
エラー文を見るとself(x)の使い方にエラーが出ていると考えています。
この書き方はPyTorch特有の書き方なのでしょうか?

質問が多く申し訳ありませんが、一つにでも答えていただけると大変ありがたいです。
よろしければご回答の程よろしくお願いします。

最後となりますが、teratailになれていないため質問の仕方等わかりずらい、ルールに基づいていない等あると思います。
その際は是非ご指摘お願いします。

#5つ目
class Net(nn.Module):

    def __init__(self, n_in, n_mid, n_out):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(n_in, n_mid)
        self.fc2 = nn.Linear(n_mid, n_mid)
        self.actor = nn.Linear(n_mid, n_out)  # 行動を決めるので出力は行動の種類数
        self.critic = nn.Linear(n_mid, 1)  # 状態価値なので出力は1つ

    def forward(self, x):
        '''ネットワークのフォワード計算を定義します'''
        h1 = F.relu(self.fc1(x))
        h2 = F.relu(self.fc2(h1))
        critic_output = self.critic(h2)  # 状態価値の計算
        actor_output = self.actor(h2)  # 行動の計算

        return critic_output, actor_output

    def act(self, x):
        '''状態xから行動を確率的に求めます'''
        value, actor_output = self(x)
        # dim=1で行動の種類方向にsoftmaxを計算
        action_probs = F.softmax(actor_output, dim=1)
        action = action_probs.multinomial(num_samples=1)  # dim=1で行動の種類方向に確率計算
        return action
#自作
class A:
    def __init__(self,a1):
        self.unk = a1

    def forward(self,x):
        y = x + 2
        z = x*3
        print("forwardに入った")
        return y,z

    def act(self,x):
        print("actに入った")
        y,z = self(x)
        return y,z


a = A(1)
print(a.act(5))

#エラー文
TypeError: 'A' object is not callable
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

質問2

self(x)とは何ですか?

self は自身のインスタンスを指します。
Python では、インスタンスに対して、() で関数のように呼び出す (例: myobj()) と関数呼び出しといって特殊メソッド __call__() が呼ばれます。
なので、self() は自身のインスタンスの関数呼び出しになります。

__call__でクラスインスタンスを関数のように呼び出す - Qiita

class Myclass:
    def __call__(self, x):
        return x + 1

obj = Myclass()
print(obj(1))  # 2

質問1

無いのであればなぜこの関数は書かれていて、他のどこでニューラルネットワークに学習データを与えているのでしょうか?

Pytorch では、nn.Module クラスの __call__() 関数内で forward() を呼び出すようになっています。
なので、nn.Module クラスを継承したクラスで forward() 関数を実装しておけば、そのクラスのインスタンスに対して、() で関数呼び出ししたら、実質的に forward() の中身が呼ばれるという仕組みです。

質問3

以下に質問2に対する自分の理解の為に作成したコードとエラー文を載せておきます。

TypeError: 'A' object is not callable
型エラー: オブジェクト A は関数呼び出し可能ではありません。

callable (呼び出し可能) とは、() で関数呼び出しができるという要件を意味しますが、質問のコードだと、__call__() が実装されていないクラス A に対して、関数呼び出ししようとしているので、できないいうエラーです。

「nn.Module を継承したクラスで forward() を実装すると、model() のように呼び出した際に forward() が呼ばれる事」は以下のコードで説明がつきます。

class Myclass:
    def __call__(self, x):
        return self.hoge(x)

    def hoge():
        pass


class MySubClass(Myclass):
    def hoge(self, x):  # 親クラスの関数 hoge() をオーバーライド
        return x + 1


obj = MySubClass()
print(obj(1))  # 2

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/01 08:27

    ご回答ありがとうございます。
    質問2及び3について理解できました。
    質問1についてさらに詳しく教えてもらいたいのですが、よろしければご回答お願いします。
    forward関数が自動で呼び出される仕組みがあることは理解しました。
    しかし、どこでfowarardに引数を渡しているのでしょうか。
    記載したURLの8つ目のセルでは
    actor_critic = Net(n_in, n_mid, n_out)
    となっており、ここでは初期化メソッドの引数しか与えていないように見えます。

    キャンセル

  • 2020/07/01 11:03 編集

    actor_critic = Net(n_in, n_mid, n_out) はコンストラクタの呼び出しです。
    探すべきなのは作成したオブジェクト actor_critic に対する () による関係呼び出しです。コードを探してみると、
    evaluate_actions() 内の Net クラスの関数内に self(x) が3箇所ありますね。

    キャンセル

  • 2020/07/01 22:18

    コメントへの返信ありがとうございます。
    nn.Moduleには__call__メソッドがあるため、そのサブクラスNetも__call___メソッドを持っている。
    self()によって、__call__メソッドを呼び出すことによって、自動的にfowatdメソッドの呼び出しにつながる仕組みになっていると理解しました。
    長々と付き合っていただき感謝しています。
    本当にありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.10%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる