【PyTorchチュートリアル】WHAT IS TORCH.NN REALLY?の7、DataLoaderのラッピング~まとめ

1_プログラミング

やっと「WHAT IS TORCH.NN REALLY?」を最後まで行きました。

PyTorchの基本的な部分はだいぶ理解できて来たかな?

PyTorchのチュートリアル「WHAT IS TORCH.NN REALLY?」のWrapping DataLoaderの項目から進めていきます。正直、今回の項目は、少し理解しきれていないのです、そのため、ほぼ翻訳となってしまっています点、ご了承ください。

こんな人の役に立つかも

・機械学習プログラミングを勉強している人

・PyTorchチュートリアルをしている人

スポンサーリンク

DataLoaderのラッピング

今まで作成してきたCNNは簡潔にできていますが、MNISTデータでのみうまく機能します。 その原因としては

・入力を28×28のデータであると想定

・最後の「Average Pooling」のカーネルサイズが4×4である

これらを仮定しているため、MNIST画像データに特化しているといえます。

このような仮定を取り除き、1チャンネルの2次元画像で機能するようなモデルに変更していきます。

まずは、最初のLambdaレイヤーを取り除き、ここで行っていたデータの前処理を「ジェネレータ」

#ラベルも返すようになりました。
def preprocess(x, y):
    return x.view(-1, 1, 28, 28), y


class WrappedDataLoader:
    def __init__(self, dl, func):
        self.dl = dl
        self.func = func

    def __len__(self):
        return len(self.dl)

    def __iter__(self):
        batches = iter(self.dl)
        for b in batches:
            yield (self.func(*b))

train_dl, valid_dl = get_data(train_ds, valid_ds, bs)
train_dl = WrappedDataLoader(train_dl, preprocess)
valid_dl = WrappedDataLoader(valid_dl, preprocess)

次に、nn.AvgPool2dをnn.AdaptiveAvgPool2dで置き換えます。これにより、入力テンソルではなく、必要な出力テンソルのサイズを定義できます。その結果、モデルは任意のサイズの入力で機能します。

model = nn.Sequential(
    #ここにLambdaがなくなりました。
    nn.Conv2d(1, 16, kernel_size=3, stride=2, padding=1),
    nn.ReLU(),
    nn.Conv2d(16, 16, kernel_size=3, stride=2, padding=1),
    nn.ReLU(),
    nn.Conv2d(16, 10, kernel_size=3, stride=2, padding=1),
    nn.ReLU(),
    nn.AdaptiveAvgPool2d(1),
    Lambda(lambda x: x.view(x.size(0), -1)),
)

opt = optim.SGD(model.parameters(), lr=lr, momentum=0.9)

訓練を行います。

fit(epochs, model, loss_func, opt, train_dl, valid_dl)

ここの項目については、サイズといわれているのが画像サイズなのか、バッチサイズなのか、いまいち理解できていません。preprocessの4階テンソルの後ろ二つが28,28なので、以前画像サイズは28×28を入れなければいけないと思っているので、画像サイズからこのモデルが解放されているような気がしない、という点が引っ掛かっています。

もう少し畳み込みニューラルネットについて勉強しないといけないです。

GPUを使う

CUDA対応のGPUが利用できる環境であれば、GPUを利用して、より早く演算ができるようになります。 

Google Colaboの場合は、「ランタイム」->「ランタイムのタイプの変更」->「ハードウェアアクセラレータ」をGPUに変更しておきます。

まずは、CUDAが利用できるかを確認します。

ここはいつもやっていることだね。

print(torch.cuda.is_available())

Google ColaboであればTrueと出るはずです。

True

次に、「デバイスオブジェクト」というものを作成します。

dev = torch.device(
    "cuda") if torch.cuda.is_available() else torch.device("cpu")

次に、バッチのデータをGPUへ移動させるため、「preprocess」関数でデータをGPUへ移動させるように書き換えます。

def preprocess(x, y):
    return x.view(-1, 1, 28, 28).to(dev), y.to(dev)


train_dl, valid_dl = get_data(train_ds, valid_ds, bs)
train_dl = WrappedDataLoader(train_dl, preprocess)
valid_dl = WrappedDataLoader(valid_dl, preprocess)

次のプログラムのように、モデルもGPUを指定しておきます。これで、GPUで動作させる準備が整いました。

model.to(dev)
opt = optim.SGD(model.parameters(), lr=lr, momentum=0.9)

訓練を実行してみると、前より早く訓練が行われるのがわかります。

fit(epochs, model, loss_func, opt, train_dl, valid_dl)

何となく、早くなっているような・・・

まとめ

これで、Pytorchを使用して多くのタイプのモデルをトレーニングするために使用できる一般的なデータパイプラインとトレーニングループができました。

チュートリアルでは、基本的な内容のみで、さらに「データ拡張、ハイパーパラメータ調整、モニタリングト​​レーニング、転移学習」など、追加したいことがたくさんあります。これらの機能はfastaiライブラリで利用できます。

torch.nn Modules:関数のように動作する呼び出し可能オブジェクトを作成し、状態(ニューラルネットの層の重みなどを含めることもできます。重みの勾配を0にしたり、パラメータの更新のためのループしたりできます。

Parameter:バックプロップ中に更新が必要な重みがあることをモジュールに通知するテンソルのラッパー。 require_grad属性が設定されたテンソルのみが更新されます。

Functional:活性化関数、損失関数など、および畳み込み層や線形層などの非ステートフルバージョンの層を含むモジュールです。通常は慣例によりF名前空間にインポートされます。

torch.optim:SGDなどのオプティマイザーが含まれ、バックワードステップ中にパラメーターの重みを更新します

Dataset:TensorDatasetなどのPytorchで提供されるクラスを含む、__ len__およびgetitemを持つオブジェクトの抽象インターフェースです。

DataLoader:任意のデータセットを受け取り、データのバッチを返すイテレータを作成します。

まとめ、ほぼGoogle翻訳だね・・・

Google翻訳、そのままでも結構理解できる日本語になりました。機械学習さまさまです。

fastaiや、転移学習といったキーワードがでてきましたので、こういった部分も興味がわいてきました。

GitHubに勉強に利用した、Colaboのプログラムを配置します。

タイトルとURLをコピーしました