web-dev-qa-db-ja.com

PyTorch Binary Classification-同じネットワーク構造、「より単純な」データですが、パフォーマンスが低下していますか?

PyTorch(および一般的なディープラーニング)を理解するために、いくつかの基本的な分類の例から始めました。そのような例の1つは、sklearnを使用して作成された非線形データセットを分類することです(ノートブックとして利用可能な完全なコード here )。

n_pts = 500
X, y = datasets.make_circles(n_samples=n_pts, random_state=123, noise=0.1, factor=0.2)
x_data = torch.FloatTensor(X)
y_data = torch.FloatTensor(y.reshape(500, 1))

enter image description here

これは、かなり基本的なニューラルネットを使用して正確に分類されます。

class Model(nn.Module):
    def __init__(self, input_size, H1, output_size):
        super().__init__()
        self.linear = nn.Linear(input_size, H1)
        self.linear2 = nn.Linear(H1, output_size)

    def forward(self, x):
        x = torch.sigmoid(self.linear(x))
        x = torch.sigmoid(self.linear2(x))
        return x

    def predict(self, x):
        pred = self.forward(x)
        if pred >= 0.5:
            return 1
        else:
            return 0

健康データに関心があるので、同じネットワーク構造を使用して基本的な実際のデータセットを分類することにしました。 here から1人の患者の心拍数データを取得し、91を超えるすべての値が異常としてラベル付けされるように変更しました(例:1および<= 91のすべてに0)。これは完全に恣意的ですが、分類がどのように機能するかを確認したかっただけです。この例の完全なノートブックは here です。

enter image description here

私にとって直感的でないのは、最初の例が1,000エポック後に0.0016の損失に達するのに対して、2番目の例は10,000エポック後に0.4296の損失にしか達しない理由です。

Training Loss for Example 1

Training Loss for Heart Rate Example

おそらく、心拍数の例を分類するほうがはるかに簡単だと私は考えているのは初心者です。これが私が見ているものではない理由を理解するのに役立つ洞察は素晴らしいでしょう!

14
Philip O'Brien

TL; DR

入力データは正規化されていません。

  1. x_data = (x_data - x_data.mean()) / x_data.std()を使用します
  2. 学習率を上げるoptimizer = torch.optim.Adam(model.parameters(), lr=0.01)

あなたが得るでしょう
enter image description here

たった1000回の反復で収束。

もっと詳しく

2つの例の主な違いは、最初の例のデータxは(0、0)を中心とし、分散が非常に小さいことです。
一方、2番目の例のデータは92を中心にしており、分散が比較的大きくなっています。

データのこの初期バイアスは、ランダムに 重みを初期化する の場合は考慮されません。これは、入力がおおよそ正規分布しているという仮定に基づいて行われますzero
最適化プロセスがこの大きな偏差を補償することはほとんど不可能です-したがって、モデルは次善のソリューションで動かなくなります。

入力を正規化したら、平均を減算してstdで割ると、最適化プロセスが再び安定し、すぐに適切なソリューションに収束します。

入力の正規化と重みの初期化の詳細については、セクション2.2のHe et alDelving Deep into Rectifiers:Surpassing Human-Level Performance on ImageNet Classification (ICCV 2015)。

データを正規化できない場合はどうなりますか?

何らかの理由で事前に平均データと標準データを計算できない場合でも、トレーニングプロセスの一部として _nn.BatchNorm1d_ を使用してデータを推定および正規化できます。例えば

_class Model(nn.Module):
    def __init__(self, input_size, H1, output_size):
        super().__init__()
        self.bn = nn.BatchNorm1d(input_size)  # adding batchnorm
        self.linear = nn.Linear(input_size, H1)
        self.linear2 = nn.Linear(H1, output_size)

    def forward(self, x):
        x = torch.sigmoid(self.linear(self.bn(x)))  # batchnorm the input x
        x = torch.sigmoid(self.linear2(x))
        return x
_

この変更なし入力データに変更を加えると、わずか1000エポック後に同様の収束が得られます。
enter image description here

小さなコメント

数値を安定させるには、 _nn.BCEWithLogitsLoss_ の代わりに _nn.BCELoss_ を使用することをお勧めします。このためには、forward()出力から_torch.sigmoid_を削除する必要があります。sigmoidは損失内で計算されます。
たとえば、バイナリ予測の関連するシグモイド+クロスエントロピー損失については this thread を参照してください。

16
Shai