<jupyter_start><jupyter_text>微分可能LUTモデルによるCNNでのCIFAR-10学習Differentiable LUTモデルで畳み込み層を形成して、一般的なデータに対してCNNによる回路学習を行います。<jupyter_code>import os
import numpy as np
from tqdm.notebook import tqdm

import torch
import torchvision
import torchvision.transforms as transforms

import binarybrain as bb<jupyter_output><empty_output><jupyter_text>データセットデータセットの準備には torchvision を使います<jupyter_code># configuration
net_name              = 'Cifar10DifferentiableLutCnn'
data_path             = os.path.join('./data/', net_name)
rtl_sim_path          = '../../verilog/cifar10'
rtl_module_name       = 'Cifar10LutCnn'
output_velilog_file   = os.path.join(data_path, rtl_module_name + '.v')
sim_velilog_file      = os.path.join(rtl_sim_path, rtl_module_name + '.v')

bin_mode              = True
frame_modulation_size = 7
depth_modulation_size = 15
epochs                = 32
mini_batch_size       = 32

# dataset
dataset_path = './data/'
dataset_train = torchvision.datasets.CIFAR10(root=dataset_path, train=True, transform=transforms.ToTensor(), download=True)
dataset_test  = torchvision.datasets.CIFAR10(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>Files already downloaded and verified
Files already downloaded and verified<jupyter_text>ネットワーク構築Convolution2d を使って畳み込み層を作ります。Convolution2d は指定した層を im2col と col2im で挟み込んで Lowering による畳み込みをサポートします。DenseAffine を Lowering すると一般にCNNで知られる畳み込み層になりますが、LUT-Network ではここに DifferentiableLut を組み合わせて作った層を設定することでDenseAffineとは異なる効率の良い畳み込み層を実現します。<jupyter_code># バイナリ時は BIT型を使えばメモリ削減可能
bin_dtype = bb.DType.BIT if bin_mode else bb.DType.FP32

# define network
net = bb.Sequential([
            bb.RealToBinary(frame_modulation_size=frame_modulation_size, depth_modulation_size=depth_modulation_size, bin_dtype=bin_dtype),
            bb.Sequential([
                bb.Convolution2d(  # pointwise
                    bb.Sequential([
                        bb.DifferentiableLut([512], bin_dtype=bin_dtype),
                        bb.DifferentiableLut([32*6], bin_dtype=bin_dtype),
                        bb.DifferentiableLut([32], bin_dtype=bin_dtype),
                    ]),
                    filter_size=(1, 1),
                    fw_dtype=bin_dtype),

                bb.Convolution2d(  # 32x32 -> 30x30
                    bb.Sequential([
                        bb.DifferentiableLut([512], bin_dtype=bin_dtype),
                        bb.DifferentiableLut([32*6], bin_dtype=bin_dtype),
                        bb.DifferentiableLut([32], bin_dtype=bin_dtype),
                    ]),
                    filter_size=(3, 3),
                    fw_dtype=bin_dtype),
                bb.Convolution2d(  # 30x30 -> 28x28
                    bb.Sequential([
                        bb.DifferentiableLut([1024], bin_dtype=bin_dtype),
                        bb.DifferentiableLut([64*6], bin_dtype=bin_dtype),
                        bb.DifferentiableLut([64], bin_dtype=bin_dtype),
                    ]),
                    filter_size=(3, 3),
                    fw_dtype=bin_dtype),
                bb.MaxPooling(filter_size=(2, 2), fw_dtype=bin_dtype),  # 28x28-> 14x14
            ]),
            bb.Sequential([
                bb.Convolution2d(  # 14x14-> 12x12
                    bb.Sequential([
                        bb.DifferentiableLut([1024], bin_dtype=bin_dtype),
                        bb.DifferentiableLut([64*6], bin_dtype=bin_dtype),
                        bb.DifferentiableLut([64], bin_dtype=bin_dtype),
                    ]),
                    filter_size=(3, 3),
                    fw_dtype=bin_dtype),
                bb.Convolution2d(  # 12x12-> 10x10
                    bb.Sequential([
                        bb.DifferentiableLut([2048], bin_dtype=bin_dtype),
                        bb.DifferentiableLut([128*6], bin_dtype=bin_dtype),
                        bb.DifferentiableLut([128], bin_dtype=bin_dtype),
                    ]),
                    filter_size=(3, 3),
                    fw_dtype=bin_dtype),
                bb.MaxPooling(filter_size=(2, 2), fw_dtype=bin_dtype),  # 10x10-> 5x5
            ]),
            bb.Sequential([
                bb.Convolution2d(  # 5x5-> 1x1
                    bb.Sequential([
                        bb.DifferentiableLut([1024*6],   bin_dtype=bin_dtype),
                        bb.DifferentiableLut([1024],     bin_dtype=bin_dtype),
                        bb.DifferentiableLut([10*6*6*6], bin_dtype=bin_dtype),
                        bb.DifferentiableLut([10*6*6],   bin_dtype=bin_dtype),
                        bb.DifferentiableLut([10*6],     bin_dtype=bin_dtype),
                        bb.DifferentiableLut([10],       bin_dtype=bin_dtype),
                    ]),
                    filter_size=(5, 5),
                    fw_dtype=bin_dtype),
            ]),
            bb.BinaryToReal(frame_integration_size=frame_modulation_size, bin_dtype=bin_dtype)
        ])

net.set_input_shape([3, 32, 32])

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

# print(net.get_info()) # ネットを表示<jupyter_output><empty_output><jupyter_text>学習実施学習を行います<jupyter_code>bb.load_networks(data_path, net)

# learning
loss      = bb.LossSoftmaxCrossEntropy()
metrics   = bb.MetricsCategoricalAccuracy()
optimizer = bb.OptimizerAdam()

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

for epoch in range(epochs):
    loss.clear()
    metrics.clear()

    # learning
    with tqdm(loader_train) as t:
        for images, labels in t:
            x_buf = bb.FrameBuffer.from_numpy(np.array(images).astype(np.float32))
            t_buf = bb.FrameBuffer.from_numpy(np.identity(10)[np.array(labels)].astype(np.float32))

            y_buf = net.forward(x_buf, train=True)

            dy_buf = loss.calculate(y_buf, t_buf)
            metrics.calculate(y_buf, t_buf)
            net.backward(dy_buf)

            optimizer.update()

            t.set_postfix(loss=loss.get(), acc=metrics.get())

    # test
    loss.clear()
    metrics.clear()
    for images, labels in loader_test:
        x_buf = bb.FrameBuffer.from_numpy(np.array(images).astype(np.float32))
        t_buf = bb.FrameBuffer.from_numpy(np.identity(10)[np.array(labels)].astype(np.float32))

        y_buf = net.forward(x_buf, train=False)

        loss.calculate(y_buf, t_buf)
        metrics.calculate(y_buf, t_buf)

    bb.save_networks(data_path, net)

    print('epoch[%d] : loss=%f accuracy=%f' % (epoch, loss.get(), metrics.get()))<jupyter_output><empty_output><jupyter_text>RTL(Verilog)変換FPGA化するために Verilog に変換します。インターフェースはXilinx社のAXI4 Stream Video 仕様(フレームスタートでtuserが立つ)となります。MaxPooling の単位で画像サイズが縮小されてしまうので、現状、この単位でしか変換できないため3つに分けて出力しています。<jupyter_code># export verilog
with open(output_velilog_file, 'w') as f:
    f.write('`timescale 1ns / 1ps\n\n')
    bb.dump_verilog_lut_cnv_layers(f, rtl_module_name + 'Cnv0', net[1])
    bb.dump_verilog_lut_cnv_layers(f, rtl_module_name + 'Cnv1', net[2])
    bb.dump_verilog_lut_cnv_layers(f, rtl_module_name + 'Cnv2', net[3])<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10810810810810811, 'fraction_numerical': 0.02661544793524489, 'mean_word_length': 2.4947267497603067, 'pattern_counts': {'":': 0, '<': 20, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '470439', 'license': 'MIT', 'n_tokens_mistral': 2885, 'n_tokens_neox': 2627, 'n_words': 318, 'path': 'samples/python/cifar10/Cifar10DifferentiableLutCnn.ipynb', 'repo_name': 'ryuz/BinaryBrain', 'size': '7289'}