<jupyter_start><jupyter_text>Road Follower - Train Model(モデルの学習)In this notebook we will train a neural network to take an input image, and output a set of x, y values corresponding to a target.(訳) このnotebookは、入力画像を読み込み、ターゲットに対応するx、y値のセットを出力するようにニューラルネットワークを学習します。We will be using PyTorch deep learning framework to train ResNet18 neural network architecture model for road follower application.(訳) road followerアプリのためにResNet18 neural networkアーキテクチャーモデルを学習するために、PyTorch deep learningフレームワークを使用します。<jupyter_code>! pip3 install tqdm
import torch
import torch.optim as optim
import torch.nn.functional as F
import torchvision
import torchvision.datasets as datasets
import torchvision.models as models
import torchvision.transforms as transforms
import glob
import PIL.Image
import os
import numpy as np
from tqdm import tqdm<jupyter_output><empty_output><jupyter_text>Create Dataset Instance(データセットインスタンスの作成)Here we create a custom ``torch.utils.data.Dataset`` implementation, which implements the ``__len__`` and ``__getitem__`` functions.  This classis responsible for loading images and parsing the x, y values from the image filenames.  Because we implement the ``torch.utils.data.Dataset`` class,we can use all of the torch data utilities :)(訳) ``__len__`` と ``__getitem__``関数が実装されたカスタマイズされた``torch.utils.data.Dataset`` の実装を生成します。このクラスは、画像をロードするための役割と、画像ファイル名からx、y値の値をパースして取得します。`torch.utils.data.Dataset``を実装する事で、すべてのtorchデータユーティリティを使用する事ができます。We hard coded some transformations (like color jitter) into our dataset.  We made random horizontal flips optional (in case you want to follow a non-symmetric path, like a roadwhere we need to 'stay right').  If it doesn't matter whether your robot follows some convention, you could enable flips to augment the dataset.(訳) いくつかの変換（カラージッターなど）をデータセットにハードコーディングしました。ランダムな水平反転をオプションにしました（「右にとどまる」必要がある道路のように、非対称の経路をたどる場合）。ロボットが何らかの規則に従っているかどうかが重要でない場合は、フリップを有効にしてデータセットを拡張できます<jupyter_code>def get_x(path):
    """Gets the x value from the image filename"""
    return (float(int(path[3:6])) - 50.0) / 50.0

def get_y(path):
    """Gets the y value from the image filename"""
    return (float(int(path[7:10])) - 50.0) / 50.0

class XYDataset(torch.utils.data.Dataset):
    
    def __init__(self, directory, random_hflips=False):
        self.directory = directory
        self.random_hflips = random_hflips
        self.image_paths = glob.glob(os.path.join(self.directory, '*.jpg'))
        self.color_jitter = transforms.ColorJitter(0.3, 0.3, 0.3, 0.3)
    
    def __len__(self):
        return len(self.image_paths)
    
    def __getitem__(self, idx):
        image_path = self.image_paths[idx]
        
        image = PIL.Image.open(image_path)
        x = float(get_x(os.path.basename(image_path)))
        y = float(get_y(os.path.basename(image_path)))
        
        if float(np.random.rand(1)) > 0.5:
            image = transforms.functional.hflip(image)
            x = -x
        
        image = self.color_jitter(image)
        image = transforms.functional.resize(image, (224, 224))
        image = transforms.functional.to_tensor(image)
        image = image.numpy()[::-1].copy()
        image = torch.from_numpy(image)
        image = transforms.functional.normalize(image, [0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
        
        return image, torch.tensor([x, y]).float()
    
dataset = XYDataset('dataset_xy', random_hflips=False)<jupyter_output><empty_output><jupyter_text>Split dataset into train and test sets(トレーニングとテスト用のデータセットに分ける)Once we read dataset, we will split data set in train and test sets. In this example we split train and test a 90%-10%. The test set will be used to verify the accuracy of the model we train.データセットをロードしたら、トレーニング用とテスト用のデータセットに分割します。この例では、トレーニング用が90%, テスト用が10%で分けます。テストセットは、トレーニングするモデルの精度を検証するために使用されます。<jupyter_code>test_percent = 0.1
num_test = int(test_percent * len(dataset))
train_dataset, test_dataset = torch.utils.data.random_split(dataset, [len(dataset) - num_test, num_test])<jupyter_output><empty_output><jupyter_text>Create data loaders to load data in batches(バッチでデータを読み込むためのdata loadersを作成)We use ``DataLoader`` class to load data in batches, shuffle data and allow using multi-subprocesses. In this example we use batch size of 64. Batch size will be based on memory available with your GPU and it can impact accuracy of the model.(訳) `` DataLoader``クラスは、並行したサブプロセスを使用して、データのシャッフル、バッチでのデータロードのために使用します。この例では、64のバッチサイズを使用します。バッチサイズは、GPUで使用可能なメモリに基づいており、モデルの精度に影響を与える可能性があります。<jupyter_code>train_loader = torch.utils.data.DataLoader(
    train_dataset,
    batch_size=16,
    shuffle=True,
    num_workers=4
)

test_loader = torch.utils.data.DataLoader(
    test_dataset,
    batch_size=16,
    shuffle=True,
    num_workers=4
)<jupyter_output><empty_output><jupyter_text>Define Neural Network Model (Neural netwrk modelの定義)We use ResNet-18 model available on PyTorch TorchVision. (訳) PyToch TouchVisionで使用可能なResNet-18モデルを使用します。In a process called transfer learning, we can repurpose a pre-trained model (trained on millions of images) for a new task that has possibly much less data available.(訳)*転移学習*と呼ばれる手法で、利用可能なデータがはるかに少ない状態で新しいタスクをおこなうために、事前にトレーニングされたモデル（数百万の画像でトレーニングされた）を再利用する事ができます。More details on ResNet-18 : https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.pyMore Details on Transfer Learning: https://www.youtube.com/watch?v=yofjFQddwHE (訳) ResNet-18の詳細: https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py転移学習の詳細: https://www.youtube.com/watch?v=yofjFQddwHE<jupyter_code>model = models.resnet18(pretrained=True)<jupyter_output><empty_output><jupyter_text>ResNet model has fully connect (fc) final layer with 512 as ``in_features`` and we will be training for regression thus ``out_features`` as 1(訳) ResNetのモデルは、`in_features``として、512を最終レイヤーに全結合します。そして、``out_features``2(x,y座標)にして回帰のトレーニングをおこないます。Finally, we transfer our model for execution on the GPU最後に、GPUで実行するために、モデルを転送します。<jupyter_code>model.fc = torch.nn.Linear(512, 2)
device = torch.device('cuda')
model = model.to(device)<jupyter_output><empty_output><jupyter_text>Train Regression:We train for 70 epochs and save best model if the loss is reduced. 70エポック学習し、損失が減少した場合は、ベストなモデルを保存します。<jupyter_code>NUM_EPOCHS = 70
BEST_MODEL_PATH = 'best_steering_model_xy.pth'
best_loss = 1e9

optimizer = optim.Adam(model.parameters())
epoch_list = []
train_loss_list = []
test_loss_list = []

for epoch in tqdm(range(NUM_EPOCHS)):
    
    model.train()
    train_loss = 0.0
    for images, labels in iter(train_loader):
        images = images.to(device)
        labels = labels.to(device)
        optimizer.zero_grad()
        outputs = model(images)
        loss = F.mse_loss(outputs, labels)
        train_loss += float(loss)
        loss.backward()
        optimizer.step()
    train_loss /= len(train_loader)
    
    model.eval()
    test_loss = 0.0
    for images, labels in iter(test_loader):
        images = images.to(device)
        labels = labels.to(device)
        outputs = model(images)
        loss = F.mse_loss(outputs, labels)
        test_loss += float(loss)
    test_loss /= len(test_loader)
    
    print('train loss %f, test_loss %f' % (train_loss, test_loss))
    epoch_list.append(epoch) 
    train_loss_list.append(train_loss)
    test_loss_list.append(test_loss)
    if test_loss < best_loss:
        torch.save(model.state_dict(), BEST_MODEL_PATH)
        best_loss = test_loss<jupyter_output>0%|          | 0/70 [00:00<?, ?it/s]<jupyter_text>損失(Loss)から学習が正常に動作しているか確認<jupyter_code>%matplotlib inline
import matplotlib.pyplot as plt

plt.plot(epoch_list, train_loss_list, '-b', label='train_loss_list')
plt.plot(epoch_list, test_loss_list, '-r', label='test_loss')

plt.xlabel("n iteration")
plt.legend(loc='upper left')

# show
plt.show()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10118819471061709, 'fraction_numerical': 0.01609812188577999, 'mean_word_length': 4.789940828402367, 'pattern_counts': {'":': 0, '<': 34, '<?xml version=': 0, '>': 33, 'https://': 4, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '8', 'dir': 'jupyter-structured-clean-dedup', 'id': '51961', 'license': 'MIT', 'n_tokens_mistral': 3282, 'n_tokens_neox': 3084, 'n_words': 617, 'path': 'notebooks/road_following/train_model.ipynb', 'repo_name': 'katebrighteyes/jetbot', 'size': '7827'}