<jupyter_start><jupyter_text>微分可能LUTモデルによるMNISTでの Auto Encoder 学習Differentiable LUTモデルを用いて MNIST 画像の Auto Encoder を作成してみます。ネットワークモデルにはCNNを用いています。バイナリであっても今のところある程度機能しており、一度 32ch まで圧縮した後に復元させています。  事前準備<jupyter_code>import os
import numpy as np
import matplotlib.pyplot as plt
from tqdm.notebook import tqdm

import torch
import torchvision
import torchvision.transforms as transforms

import binarybrain as bb<jupyter_output><empty_output><jupyter_text>異なる閾値で2値化した画像でフレーム数を水増ししながら学習させます。この水増しをバイナリ変調と呼んでいます。ここではフレーム方向の水増し量を frame_modulation_size で指定しています。別途 CIFAR-10などでも実験していますが、変調によりバイナリであってもある程度の階調表現の復元が行えるようです。<jupyter_code># configuration
net_name              = 'MnistAeDifferentiableLutCnn'
data_path             = os.path.join('./data/', net_name)

bin_mode              = True
epochs                = 4
mini_batch_size       = 32
frame_modulation_size = 7<jupyter_output><empty_output><jupyter_text>データセットは PyTorch の torchvision を使います。BinaryBrainではミニバッチをフレーム数として FrameBufferオブジェクトで扱います。バイナリ変調で計算中にフレーム数が変わるためデータセットの準備観点でのミニバッチと呼び分けています。<jupyter_code># dataset
dataset_path = './data/'
dataset_train = torchvision.datasets.MNIST(root=dataset_path, train=True, transform=transforms.ToTensor(), download=True)
dataset_test  = torchvision.datasets.MNIST(root=dataset_path, train=False, transform=transforms.ToTensor(), download=True)
loader_train = torch.utils.data.DataLoader(dataset=dataset_train, batch_size=mini_batch_size, shuffle=True, num_workers=2)
loader_test  = torch.utils.data.DataLoader(dataset=dataset_test,  batch_size=mini_batch_size, shuffle=False, num_workers=2)<jupyter_output><empty_output><jupyter_text>ネットワークの構築畳み込みを行い 1x1x32ch (バイナリなので32bit)まで圧縮した後に復元するネットワークを作ります。なお、最後の方の層で batch_norm=False としています。扱う画像自体が正規化されたものではないので、BatchNormalization を取り外しています。<jupyter_code># バイナリ時は BIT型を使えばメモリ削減可能
bin_dtype = bb.DType.BIT if bin_mode else bb.DType.FP32
#bin_dtype = bb.DType.FP32

# define network
net = bb.Sequential([
        bb.RealToBinary(frame_modulation_size=frame_modulation_size, bin_dtype=bin_dtype),
        
        # Encoder
        bb.Sequential([
            bb.Convolution2d(
                bb.Sequential([
                    bb.DifferentiableLut([192], bin_dtype=bin_dtype),
                    bb.DifferentiableLut([32],  bin_dtype=bin_dtype),
                ]),
                filter_size=(3, 3), padding="same", fw_dtype=bin_dtype),

            bb.Convolution2d(
                bb.Sequential([
                    bb.DifferentiableLut([192], bin_dtype=bin_dtype),
                    bb.DifferentiableLut([32],  bin_dtype=bin_dtype),
                ]),
                filter_size=(3, 3), padding="same", fw_dtype=bin_dtype),

            bb.MaxPooling(filter_size=(2, 2), fw_dtype=bin_dtype),

            bb.Convolution2d(
                bb.Sequential([
                    bb.DifferentiableLut([384], bin_dtype=bin_dtype),
                    bb.DifferentiableLut([64],  bin_dtype=bin_dtype),
                ]),
                filter_size=(3, 3), padding="same", fw_dtype=bin_dtype),

            bb.Convolution2d(
                bb.Sequential([
                    bb.DifferentiableLut([384], bin_dtype=bin_dtype),
                    bb.DifferentiableLut([64],  bin_dtype=bin_dtype),
                ]),
                filter_size=(3, 3), padding="same", fw_dtype=bin_dtype),

            bb.MaxPooling(filter_size=(2, 2), fw_dtype=bin_dtype),

            bb.DifferentiableLut([1152], bin_dtype=bin_dtype),
            bb.DifferentiableLut([192],  bin_dtype=bin_dtype),
            bb.DifferentiableLut([32],   bin_dtype=bin_dtype),
        ]),
        
        # Decoder
        bb.Sequential([
            bb.DifferentiableLut([125],      bin_dtype=bin_dtype),
            bb.DifferentiableLut([1024],     bin_dtype=bin_dtype),
            bb.DifferentiableLut([64, 7, 7], bin_dtype=bin_dtype),
            
            bb.UpSampling(filter_size=(2, 2), fw_dtype=bin_dtype),
            
            bb.Convolution2d(
                bb.Sequential([
                    bb.DifferentiableLut([384], bin_dtype=bin_dtype),
                    bb.DifferentiableLut([64],  bin_dtype=bin_dtype),
                ]),
                filter_size=(3, 3), padding="same", fw_dtype=bin_dtype),

            bb.Convolution2d(
                bb.Sequential([
                    bb.DifferentiableLut([384], bin_dtype=bin_dtype),
                    bb.DifferentiableLut([64],  bin_dtype=bin_dtype),
                ]),
                filter_size=(3, 3), padding="same", fw_dtype=bin_dtype),

            bb.UpSampling(filter_size=(2, 2), fw_dtype=bin_dtype),

            bb.Convolution2d(
                bb.Sequential([
                    bb.DifferentiableLut([192], bin_dtype=bin_dtype),
                    bb.DifferentiableLut([32],  bin_dtype=bin_dtype),
                ]),
                filter_size=(3, 3), padding="same", fw_dtype=bin_dtype),

            bb.Convolution2d(
                bb.Sequential([
                    bb.DifferentiableLut([216], bin_dtype=bin_dtype),
                    bb.DifferentiableLut([36],  batch_norm=False, bin_dtype=bin_dtype),
                    bb.DifferentiableLut([6],   batch_norm=False, bin_dtype=bin_dtype),
                    bb.DifferentiableLut([1],   batch_norm=False, bin_dtype=bin_dtype),
                ]),
                filter_size=(3, 3), padding="same", fw_dtype=bin_dtype),
        ]),
    
        bb.BinaryToReal(frame_integration_size=frame_modulation_size, bin_dtype=bin_dtype),
    ])

net.set_input_shape([1, 28, 28])

if bin_mode:
    net.send_command("binary true")
else:
    net.send_command("binary false")

loss      = bb.LossMeanSquaredError()
metrics   = bb.MetricsMeanSquaredError()
optimizer = bb.OptimizerAdam()

optimizer.set_variables(net.get_parameters(), net.get_gradients())

# print(net.get_info(3))<jupyter_output><empty_output><jupyter_text>学習の実施入力画像そのものを期待値として、損失関数には平均二乗誤差(MSE)を使います。<jupyter_code># bb.load_networks(data_path, net)

# learning
for epoch in range(epochs):
    # learning
    loss.clear()
    metrics.clear()
    with tqdm(loader_train) as t:
        for images, labels in t:
            x_buf = bb.FrameBuffer.from_numpy(np.array(images).astype(np.float32))
            y_buf = net.forward(x_buf, train=True)
            dy_buf = loss.calculate(y_buf, x_buf)
            net.backward(dy_buf)
            optimizer.update()
            t.set_postfix(loss=loss.get())

    # test
    loss.clear()
    metrics.clear()
    for images, labels in loader_test:
        x_buf = bb.FrameBuffer.from_numpy(np.array(images).astype(np.float32))
        y_buf = net.forward(x_buf, train=False)
        loss.calculate(y_buf, x_buf)
        metrics.calculate(y_buf, x_buf)

    print('epoch[%d] : loss(MSE)=%f' % (epoch, loss.get()))

    bb.save_networks(data_path, net)<jupyter_output><empty_output><jupyter_text>結果を表示してみる入力画像(x)と、一度圧縮して縮小した画像(y)の２つを10個表示してみます。<jupyter_code># 最新の保存データ読み込み
#bb.load_networks(data_path, net)
for images, labels in loader_test:
    x_buf = bb.FrameBuffer.from_numpy(np.array(images).astype(np.float32))
    y_buf = net.forward(x_buf, train=False)
    break
x = x_buf.numpy()
y = y_buf.numpy()
plt.figure(figsize=(12,4))
for i in range(10):
    plt.subplot(2, 10, i+1)
    plt.title('x[%d]'%i)
    plt.imshow(x[i][0], 'gray')
    plt.subplot(2, 10, i+11)
    plt.title('y[%d]'%i)
    plt.imshow(y[i][0], 'gray')
plt.tight_layout()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11695120311869875, 'fraction_numerical': 0.019626293856701168, 'mean_word_length': 2.9178515007898893, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '67039', 'license': 'MIT', 'n_tokens_mistral': 3102, 'n_tokens_neox': 2874, 'n_words': 331, 'path': 'tests/python/mnist/MnistAeDifferentiableLutCnn.ipynb', 'repo_name': 'ryuz/BinaryBrain', 'size': '7439'}