専門ユニット2/山内研セミナー(2023/10/24)

関連サイトと資料

2.開発環境

その1
%%time
  
import torch
from torch import optim
import torch.nn as nn
import torch.nn.functional as F
from torchvision.datasets import CIFAR10
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
  
cifar10_train = CIFAR10("./data", train=True, download=True, transform=transforms.ToTensor())
cifar10_test = CIFAR10("./data", train=False, download=True, transform=transforms.ToTensor())
  
batch_size = 64
train_loader = DataLoader(cifar10_train, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(cifar10_test, batch_size=len(cifar10_test), shuffle=False)
  
class Net(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=6, kernel_size=5)
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
        self.conv2 = nn.Conv2d(in_channels=6, out_channels=16, kernel_size=5)
        self.fc1 = nn.Linear(in_features=16*5*5, out_features=256)
        self.fc2 = nn.Linear(in_features=256, out_features=10)
  
    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16*5*5)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return x
  
net = Net()
if torch.cuda.is_available():
    net.cuda()
  
loss_fnc = nn.CrossEntropyLoss()
optimizer = optim.Adam(net.parameters())
  
record_loss_train = []
record_loss_test = []
  
x_test, t_test = next(iter(test_loader))
if torch.cuda.is_available():
    x_test, t_test = x_test.cuda(), t_test.cuda()
  
for i in range(10):
    net.train()
    loss_train = 0
    for j, (x, t) in enumerate(train_loader):
        if torch.cuda.is_available():
            x, t = x.cuda(), t.cuda()
        y = net(x)
        loss = loss_fnc(y, t)
        loss_train += loss.item()
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    loss_train /= j+1
    record_loss_train.append(loss_train)
  
    net.eval()
    y_test = net(x_test)
    loss_test = loss_fnc(y_test, t_test).item()
    record_loss_test.append(loss_test)
    

3.PyTorchで実装する簡単な深層学習

Tensor

その2

import torch
    
a = torch.tensor([1,2,3])
print(a, type(a))
    

その3

print("--- 2次元のリストから生成 ---")
b = torch.tensor([[1, 2],
                  [3, 4]])
print(b)
  
print("--- dypeを指定し、倍精度のTensorにする ---")
c = torch.tensor([[1, 2],
                  [3, 4]], dtype=torch.float64)
print(c)
  
print("--- 0から9までの数値で初期化 ---")
d = torch.arange(0, 10)
print(d)
  
print("--- 全ての値が0の、2×3のTensor ---")
e = torch.zeros(2, 3)
print(e)
  
print("--- 全ての値が乱数の、2×3のTensor ---")
f = torch.rand(2, 3)
print(f)
  
print("--- Tensorの形状はsizeメソッドで取得 ---")
print(f.size())
    

その4

print("--- -5から5までの連続値を10生成 ---")
g = torch.linspace(-5, 5, 10)
print(g)
    

その5

print("--- Tensor → NumPy ---")
a = torch.tensor([[1, 2],
                  [3, 4.]])
b = a.numpy()
print(b)
  
print("--- NumPy → Tensor ---")
c = torch.from_numpy(b)
print(c)
    

その6

a = torch.tensor([[1, 2, 3],
                  [4, 5, 6]])
  
print("--- 2つのインデックスを指定 ---")
print(a[0, 1])
  
print("--- 範囲を指定 ---")
print(a[1:2, :2])
  
print("--- リストで複数のインデックスを指定 ---")
print(a[:, [0, 2]])
  
print("--- 3より大きい要素のみを指定 ---")
print(a[a>3])
  
print("--- 要素の変更 ---")
a[0, 2] = 11
print(a)
  
print("--- 要素の一括変更 ---")
a[:, 1] = 22
print(a)
  
print("--- 10より大きい要素のみ変更 ---")
a[a>10] = 33
print(a)
    

その7

# ベクトル
a = torch.tensor([1, 2, 3]) 
b = torch.tensor([4, 5, 6])
  
# 行列
c = torch.tensor([[6, 5, 4],
                  [3, 2, 1]])
  
print("--- ベクトルとスカラーの演算 ---")
print(a + 3)
  
print("--- ベクトル同士の演算 ---")
print(a + b) 
  
print("--- 行列とスカラーの演算 ---")
print(c + 2)
  
print("--- 行列とベクトルの演算(ブロードキャスト) ---")
print(c + a)
  
print("--- 行列同士の演算 ---")
print(c + c)
    

その8

a = torch.tensor([0, 1, 2, 3, 4, 5, 6, 7])  # 1次元のTensor
b = a.view(2, 4)  # (2, 4)の2次元のTensorに変換
print(b)
    

その9

c = torch.tensor([0, 1, 2, 3, 4, 5, 6, 7])  # 1次元のTensor
d = c.view(2, -1)  # (2, 4)の2次元のTensorに変換
print(d)
    

その10

e = torch.tensor([[[0, 1],
                   [2, 3]], 
                  [[4, 5],
                   [6, 7]]])  # 3次元のTensor
f = c.view(-1)  # 1次元のTensorに変換
print(f)
    

その11

print("--- 要素数が1の次元が含まれる4次元のTensor ---")
g = torch.arange(0, 8).view(1, 2, 1, 4)
print(g)
  
print("--- 要素数が1の次元を削除 ---")
h = g.squeeze()
print(h)
    

その12

print("--- 2次元のTensor ---")
i = torch.arange(0, 8).view(2, -1)
print(i)
  
print("--- 要素数が1の次元を、一番内側(2)に追加 ---")
j = i.unsqueeze(2)
print(j)
    

その13

a = torch.tensor([[1, 2, 3],
                  [4, 5, 6.]])
  
print("--- 平均値を求める関数 ---")
m = torch.mean(a)
print(m.item())  # item()で値を取り出す
  
print("--- 平均値を求めるメソッド ---")
m = a.mean()
print(m.item())
  
print("--- 列ごとの平均値 ---")
print(a.mean(0))
  
print("--- 合計値 ---")
print(torch.sum(a).item())
  
print("--- 最大値 ---")
print(torch.max(a).item())
  
print("--- 最小値 ---")
print(torch.min(a).item())
    

その14

import torch
  
a = torch.tensor([[1, 2, 3],
                  [4, 5, 6]])
b = torch.tensor([1, 2, 3]) 
  
print("--- 和 ---")
print(a + b)
  
print("--- 差 ---")
print(a - b)
  
print("--- 積 ---")
print(a * b)
  
print("--- 商(小数) ---")
print(a / b)
  
print("--- 商(整数) ---")
print(a // b)
  
print("--- 余り ---")
print(a % b)
    

活性化関数

その15

import torch
from torch import nn
import matplotlib.pylab as plt
  
m = nn.Sigmoid()  # シグモイド関数
  
x = torch.linspace(-5, 5, 50)
y = m(x)
  
plt.plot(x, y)
plt.show()
    

その16

import torch
from torch import nn
import matplotlib.pylab as plt
  
m = nn.Tanh()  # tanh
  
x = torch.linspace(-5, 5, 50)
y = m(x)
  
plt.plot(x, y)
plt.show()
    

その17

import torch
from torch import nn
import matplotlib.pylab as plt
  
m = nn.ReLU()  # ReLU
  
x = torch.linspace(-5, 5, 50)
y = m(x)
  
plt.plot(x, y)
plt.show()
    

その18

mport torch
import matplotlib.pylab as plt
  
x = torch.linspace(-5, 5, 50)
y = x  # 恒等関数
  
plt.plot(x, y)
plt.show()
    

その19

import torch
from torch import nn
import matplotlib.pylab as plt
  
m = nn.Softmax(dim=1)  # 各行でソフトマックス関数
  
x = torch.tensor([[1.0, 2.0, 3.0],
                  [3.0, 2.0, 1.0]])
y = m(x)
  
print(y)
    

その20

import torch
import matplotlib.pylab as plt
  
x = torch.linspace(-5, 5, 50)
y = torch.sigmoid(x)
  
plt.plot(x, y)
plt.show()
    

損失関数

その21

import torch
from torch import nn

y = torch.tensor([3.0, 3.0, 3.0, 3.0, 3.0])  # 出力
t = torch.tensor([2.0, 2.0, 2.0, 2.0, 2.0])  # 正解

loss_func = nn.MSELoss()  # 平均二乗誤差
loss = loss_func(y, t)
print(loss.item())
    

その22

import torch
from torch import nn
  
# ソフトマックス関数への入力
x = torch.tensor([[1.0, 2.0, 3.0],  # 入力1
                  [3.0, 1.0, 2.0]])  # 入力2
# 正解(one-hot表現における1の位置)
t = torch.tensor([2,  # 入力1に対応する正解
                  0])  # 入力2に対応する正解
  
loss_func = nn.CrossEntropyLoss()  # ソフトマックス関数 + 交差エントロピー誤差
loss = loss_func(x, t)
print(loss.item())
    

シンプルな深層学習の実装

その23

import matplotlib.pyplot as plt
from sklearn import datasets
  
digits_data = datasets.load_digits()
  
n_img = 10  # 表示する画像の数
plt.figure(figsize=(10, 4))
for i in range(n_img):
    ax = plt.subplot(2, 5, i+1)
    ax.imshow(digits_data.data[i].reshape(8, 8), cmap="Greys_r")
    ax.get_xaxis().set_visible(False)  # 軸を非表示に
    ax.get_yaxis().set_visible(False)
plt.show()
  
print("データの形状:", digits_data.data.shape)
print("ラベル:", digits_data.target[:n_img])
    

その24

import torch
from sklearn.model_selection import train_test_split
  
digit_images = digits_data.data
labels = digits_data.target
x_train, x_test, t_train, t_test = train_test_split(digit_images, labels)  # 25%がテスト用
  
# Tensorに変換
x_train = torch.tensor(x_train, dtype=torch.float32)  # 入力: 訓練用
t_train = torch.tensor(t_train, dtype=torch.int64)  # 正解: 訓練用
x_test = torch.tensor(x_test, dtype=torch.float32)  # 入力: テスト用
t_test = torch.tensor(t_test, dtype=torch.int64)  # 正解: テスト用
    

その25

from torch import nn
  
net = nn.Sequential(
    nn.Linear(64, 32),  # 全結合層
    nn.ReLU(),          # ReLU
    nn.Linear(32, 16),
    nn.ReLU(),
    nn.Linear(16, 10)
)
print(net)
    

その26

from torch import optim
  
# ソフトマックス関数 + 交差エントロピー誤差関数
loss_fnc = nn.CrossEntropyLoss()
  
# SGD モデルのパラメータを渡す
optimizer = optim.SGD(net.parameters(), lr=0.01)  # 学習率は0.01
  
# 損失のログ
record_loss_train = []
record_loss_test = []
  
# 訓練データを1000回使う
for i in range(1000):
  
    # パラメータの勾配を0に
    optimizer.zero_grad()
    
    # 順伝播
    y_train = net(x_train)
    y_test = net(x_test)
    
    # 誤差を求めて記録する
    loss_train = loss_fnc(y_train, t_train)
    loss_test = loss_fnc(y_test, t_test)
    record_loss_train.append(loss_train.item())
    record_loss_test.append(loss_test.item())
  
    # 逆伝播(勾配を計算)
    loss_train.backward()
    
    # パラメータの更新
    optimizer.step()
  
    if i%100 == 0:  # 100回ごとに経過を表示
        print("Epoch:", i, "Loss_Train:", loss_train.item(), "Loss_Test:", loss_test.item())
    

その27

plt.plot(range(len(record_loss_train)), record_loss_train, label="Train")
plt.plot(range(len(record_loss_test)), record_loss_test, label="Test")
plt.legend()
  
plt.xlabel("Epochs")
plt.ylabel("Error")
plt.show()
    

その28

y_test = net(x_test)
count = (y_test.argmax(1) == t_test).sum().item()
print("正解率:", str(count/len(y_test)*100) + "%")
    

その29

# 入力画像
img_id = 0
x_pred = digit_images[img_id]
image = x_pred.reshape(8, 8)
plt.imshow(image, cmap="Greys_r")
plt.show()
  
x_pred = torch.tensor(x_pred, dtype=torch.float32)
y_pred = net(x_pred)
print("正解:", labels[img_id], "予測結果:", y_pred.argmax().item())