リカレント ニューラル ネットワークによるフル解像度の画像圧縮 コードの変更と学習

コードと紙のリソース

コードリンク

コード

ペーパーリンク

コードの修正

GitHub からコードをダウンロードしたときに、完全に実行できないことがわかりました。これは主に、GitHub コードで使用されている pytorch のバージョンがバージョン 0.4 よりも遅れており、私のコンピュータにインストールされているバージョンが比較的高かったためです。 GitHub では、操作はコマンド ラインで直接実行されるため、その後のデバッグには役立たないため、この記事はこれらの問題に対処するために変更されます。

コマンドラインの変更

列車改造

ここに画像の説明を挿入します
train で次のように変更します。

`parser = argparse.ArgumentParser()
	parser.add_argument(
	    '--batch-size', '-N', type=int, default=32, help='batch size')
	parser.add_argument(
	    '--train', '-f', default=r'C:\Users\scp\Desktop\pytorch-image-comp-rnn000\val2014', type=str, help='folder of training images')
	parser.add_argument(
	    '--max-epochs', '-e', type=int, default=20, help='max epochs')
	parser.add_argument('--lr', type=float, default=0.0005, help='learning rate') parser.add_argument('--cuda', '-g', action='store_true', help='enables cuda')
	parser.add_argument(
	    '--iterations', type=int, default=16, help='unroll iterations')
	parser.add_argument('--checkpoint', type=int, help='unroll iterations')
	args = parser.parse_args()`

エンコーダの修正

ここに画像の説明を挿入します
エンコーダで次のように変更します。

`parser = argparse.ArgumentParser()
parser.add_argument(
    '--model', '-m', type=str, default=r'D:\PycharmProjects\pytorch-image-comp-rnn-master\checkpoint\encoder_epoch_00000016.pth',help='path to model')
parser.add_argument(
    '--input', '-i',  type=str,default=r'D:\PycharmProjects\pytorch-image-comp-rnn-master\c797b84fc2bdb71e5b6641af1f2b0d4b.jpg', help='input image')
parser.add_argument(
    '--output', '-o',type=str,default='ex',  help='output codes')
parser.add_argument('--cuda', '-g', action='store_true', help='enables cuda')
parser.add_argument(
    '--iterations', type=int, default=16, help='unroll iterations')
args = parser.parse_args()

デコーダの修正

ここに画像の説明を挿入します
デコーダで次のように変更します。

`arser = argparse.ArgumentParser()
parser.add_argument('--model',  type=str, default=r'D:\PycharmProjects\pytorch-image-comp-rnn-master\checkpoint\decoder_epoch_00000016.pth',help='path to model')
parser.add_argument('--input',  type=str,default=r'D:\PycharmProjects\pytorch-image-comp-rnn-master\ex.npz', help='input codes')
parser.add_argument('--output', default=r'D:\PycharmProjects\pytorch-image-comp-rnn-master\test\images', type=str, help='output folder')
parser.add_argument('--cuda', action='store_true', help='enables cuda')
parser.add_argument(
    '--iterations', type=int, default=16, help='unroll iterations')
args = parser.parse_args()

一部のコード変更と互換性のあるバージョン

UserWarning:lr_scheduler.step()以前の呼び出しを検出しましたoptimizer.step()PyTorch 1.1.0 以降では、これらを逆の順序 (optimizer.step()の前 )で呼び出す必要がありますlr_scheduler.step()これを行わないと、PyTorch は学習率スケジュールの最初の値をスキップします。詳細については、https://pytorch.org/docs/stable/optim.html#how-to-adjust-learning-rate
warnings.warn("lr_scheduler.step()以前の呼び出しが検出されましたoptimizer.step()。 " を参照してください。

この警告は、次のエラー コードに示すように、エラーにあるように、「optimizer.step()」の前に「lr_scheduler.step()」が呼び出されるために train で発生します。

for epoch in range(last_epoch + 1, args.max_epochs + 1):

    scheduler.step()

    for batch, data in enumerate(train_loader):
        batch_t0 = time.time()

        ## init lstm state
        encoder_h_1 = (Variable(torch.zeros(data.size(0), 256, 8, 8).cuda()),
                       Variable(torch.zeros(data.size(0), 256, 8, 8).cuda()))
        encoder_h_2 = (Variable(torch.zeros(data.size(0), 512, 4, 4).cuda()),
                       Variable(torch.zeros(data.size(0), 512, 4, 4).cuda()))
        encoder_h_3 = (Variable(torch.zeros(data.size(0), 512, 2, 2).cuda()),
                       Variable(torch.zeros(data.size(0), 512, 2, 2).cuda()))

        decoder_h_1 = (Variable(torch.zeros(data.size(0), 512, 2, 2).cuda()),
                       Variable(torch.zeros(data.size(0), 512, 2, 2).cuda()))
        decoder_h_2 = (Variable(torch.zeros(data.size(0), 512, 4, 4).cuda()),
                       Variable(torch.zeros(data.size(0), 512, 4, 4).cuda()))
        decoder_h_3 = (Variable(torch.zeros(data.size(0), 256, 8, 8).cuda()),
                       Variable(torch.zeros(data.size(0), 256, 8, 8).cuda()))
        decoder_h_4 = (Variable(torch.zeros(data.size(0), 128, 16, 16).cuda()),
                       Variable(torch.zeros(data.size(0), 128, 16, 16).cuda()))

        patches = Variable(data.cuda())

        solver.zero_grad()

        losses = []

        res = patches - 0.5

        bp_t0 = time.time()

        for _ in range(args.iterations):
            encoded, encoder_h_1, encoder_h_2, encoder_h_3 = encoder(
                res, encoder_h_1, encoder_h_2, encoder_h_3)

            codes = binarizer(encoded)

            output, decoder_h_1, decoder_h_2, decoder_h_3, decoder_h_4 = decoder(
                codes, decoder_h_1, decoder_h_2, decoder_h_3, decoder_h_4)

            res = res - output
            losses.append(res.abs().mean())

        bp_t1 = time.time()

        loss = sum(losses) / args.iterations
        loss.backward()

        solver.step()

        batch_t1 = time.time()

        print(
            '[TRAIN] Epoch[{}]({}/{}); Loss: {:.6f}; Backpropagation: {:.4f} sec; Batch: {:.4f} sec'.
            format(epoch, batch + 1,
                   len(train_loader), loss.data, bp_t1 - bp_t0, batch_t1 -
                   batch_t0))
        print(('{:.4f} ' * args.iterations +
               '\n').format(* [l.data for l in losses]))

        index = (epoch - 1) * len(train_loader) + batch

        ## save checkpoint every 500 training steps
        if index % 500 == 0:
            save(0, False)

    save(epoch)

着替える:

for epoch in range(last_epoch + 1, args.max_epochs + 1):



    for batch, data in enumerate(train_loader):
        batch_t0 = time.time()

        ## init lstm state
        encoder_h_1 = (Variable(torch.zeros(data.size(0), 256, 8, 8).cuda()),
                       Variable(torch.zeros(data.size(0), 256, 8, 8).cuda()))
        encoder_h_2 = (Variable(torch.zeros(data.size(0), 512, 4, 4).cuda()),
                       Variable(torch.zeros(data.size(0), 512, 4, 4).cuda()))
        encoder_h_3 = (Variable(torch.zeros(data.size(0), 512, 2, 2).cuda()),
                       Variable(torch.zeros(data.size(0), 512, 2, 2).cuda()))

        decoder_h_1 = (Variable(torch.zeros(data.size(0), 512, 2, 2).cuda()),
                       Variable(torch.zeros(data.size(0), 512, 2, 2).cuda()))
        decoder_h_2 = (Variable(torch.zeros(data.size(0), 512, 4, 4).cuda()),
                       Variable(torch.zeros(data.size(0), 512, 4, 4).cuda()))
        decoder_h_3 = (Variable(torch.zeros(data.size(0), 256, 8, 8).cuda()),
                       Variable(torch.zeros(data.size(0), 256, 8, 8).cuda()))
        decoder_h_4 = (Variable(torch.zeros(data.size(0), 128, 16, 16).cuda()),
                       Variable(torch.zeros(data.size(0), 128, 16, 16).cuda()))

        patches = Variable(data.cuda())

        solver.zero_grad()

        losses = []

        res = patches - 0.5

        bp_t0 = time.time()

        for _ in range(args.iterations):
            encoded, encoder_h_1, encoder_h_2, encoder_h_3 = encoder(
                res, encoder_h_1, encoder_h_2, encoder_h_3)

            codes = binarizer(encoded)

            output, decoder_h_1, decoder_h_2, decoder_h_3, decoder_h_4 = decoder(
                codes, decoder_h_1, decoder_h_2, decoder_h_3, decoder_h_4)

            res = res - output
            losses.append(res.abs().mean())

        bp_t1 = time.time()

        loss = sum(losses) / args.iterations
        loss.backward()

        solver.step()

        batch_t1 = time.time()

        print(
            '[TRAIN] Epoch[{}]({}/{}); Loss: {:.6f}; Backpropagation: {:.4f} sec; Batch: {:.4f} sec'.
            format(epoch, batch + 1,
                   len(train_loader), loss.data, bp_t1 - bp_t0, batch_t1 -
                   batch_t0))
        print(('{:.4f} ' * args.iterations +
               '\n').format(* [l.data for l in losses]))

        index = (epoch - 1) * len(train_loader) + batch

        ## save checkpoint every 500 training steps
        if index % 500 == 0:
            save(0, False)
    scheduler.step()
    save(epoch)

したがって、lr_scheduler.step() は各エポック トレーニングの完了後に配置する必要があります。
ここに画像の説明を挿入します
前述の通り、バージョンの都合上、from scipy.misc import imread、imresize、imsave を
from imageio import imread、imsave に置き換える必要があり、その他の部分も修正されています。

ここに画像の説明を挿入します
この警告は、コードの上の部分に表示されます:
UserWarning: volatile は削除され、現在は効果がありません。 torch.no_grad() とともに使用します: 代わりに.self.priors = Variable(self.priorbox.forward(), volatile=True) )
これは、エラーが volatile がもう役に立たないことを示しているためです。その理由は、バージョンが繰り返されると、その必要がなくなるためです。torch.no_grad() で使用するには: したがって、変更は次
ここに画像の説明を挿入します
のようになります: 他の部分にも同じことが
当てはまります。参考は次のとおりです:リンクの説明
他の部分のエラー:
warnings.warn("nn.function.tanh は非推奨です。代わりに torch.tanh です。") これもバージョン上の理由により変更前です

ingate = F.sigmoid(ingate)
        forgetgate = F.sigmoid(forgetgate)
        cellgate = F.tanh(cellgate)
        outgate = F.sigmoid(outgate)

変更後:

ingate = torch.sigmoid(ingate)
        forgetgate = torch.sigmoid(forgetgate)
        cellgate = torch.tanh(cellgate)
        outgate = torch.sigmoid(outgate)

他の部分も同様です。

論文解釈

リカレントニューラルネットワークに基づく画像圧縮方式

RNN は 1980 年代に登場し、当初は実装の難しさからあまり普及していませんでしたが、その後、RNN の構造の進歩や GPU の性能の向上により、徐々に普及し、現在では RNN はさまざまな分野で多くの成果をあげています。音声認識、機械翻訳などの結果。CNN と比較すると、RNN は CNN と同じパラメータ共有特性を持っています。違いは、CNN のパラメータ共有が空間的であるのに対し、RNN は時間的、つまりシーケンスベースであることです。これにより、RNN は以前のシーケンス情報を理解する能力を持ちます。 「記憶」に加えて、トレーニング方法は勾配降下法によって反復的に前方計算を行うことです。これら 2 つの方法では、まずデータ圧縮の程度を向上させることができ、次に反復方法によって画像のビット レートを制御することができ、どちらも画像の圧縮パフォーマンスを向上させることができます。

したがって、RNN を使用した画像圧縮は、フル解像度の画像圧縮とコード レートによる圧縮率の制御の両方で比較的良好な結果を達成していますが、RNN を使用する場合、ほとんどの場合、LSTM[1] またはGRU[2] ] は長期的な依存関係の問題を解決するため、モデルのトレーニングはより複雑になります。
RNN と LSTM の原則

この記事で使用している画像圧縮方式

Toderici et al. [3] は畳み込み LSTM を初めて用いて、可変ビットレートでの End-to-End 学習画像圧縮を実現しており、RNN を画像圧縮に利用する代表的な手法と言えます。与えられた画質の条件下では、現在の最適な圧縮率よりも優れた再構成画質効果を得ることができますが、この効果は 32×32 サイズの画像に限定されており、画像の依存関係をキャプチャする際のこの方法の欠点を示しています。 . この問題を解決するために。Toderici et al. [4] は、画像内のパッチ間の長期依存関係を捕捉できるだけでなく、2 つの可能な方法を組み合わせて所定の品質の圧縮率を向上させることができる残差ブロックベースの残差エンコーダーとエントロピー エンコーダーを設計しています。フル解像度の画像圧縮を実現します。この方法では、RNN 勾配降下トレーニング法を使用して、フル解像度に基づく非可逆画像圧縮方法を提案します。

その構造を図に示します。この方法には、Encoder エンコード、Binarizer バイナリ化、Decoder デコードという 3 つの主要な部分が含まれています。入力画像はまずエンコードされ、次に保存またはデコーダに送信できるバイナリ コードに変換されます。

エンコード部分は 1 つの CNN と 3 つの RNN で構成され、Encoder デコーダ ネットワークは受信したバイナリ コードに基づいて元の入力画像の推定値を作成します。

Binarizer の二値化部分は主に RNN を通じて実行されます。
デコーダのデコード部分は、畳み込み巡回ネットワーク構造を使用して信号を反復して元の画像を復元します。反復プロセス中に重みが共有され、各反復で 2 進数のビットが生成されます。ネットワークは現在の残差から新しい情報を抽出し、それをリカレント層の隠れ状態に保存されているコンテキストと組み合わせて、この情報を通じて画像の再構成を実現します。RNN を使用したこの方法の成功は誰の目にも明らかであり、より多くの人々が画像圧縮に注目するようになりました。

Toderici が使用する RNN 画像圧縮フレームワーク:
ここに画像の説明を挿入します

参考文献

[1] Hochreiter S、Schmidhuber J.長期短期記憶[J]。
神経計算,1997,9(8).

[2]Chung J、Gulcehre C、Cho KH、et al.
シーケンス モデリングに関するゲート型リカレント ニューラル ネットワークの経験的評価[J].arXiv:1412.3555、2014。
[3]Toderici G、O'Malley SM、Hwang SJ、他、
リカレント ニューラル ネットワークによる可変レート画像圧縮[J]。arXiv:1511.06085、2015. [4]Toderici G,Vincent D,Johnston N,et al .リカレント ニューラル ネットワークによるフル
解像度画像圧縮[C]// Proceedings of the IEEE Con​​ference on Computer Vision and Pattern Recognition,2017:5306-5314.

おすすめ

転載: blog.csdn.net/officewords/article/details/130181921