やっと「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を使う
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のプログラムを配置します。