専門ユニット2/山内研セミナー(2023/11/21)
関連サイトと資料
6.RNN(再帰型ニューラルネットワーク)
シンプルなRNNの実装
その1
import torch
import math
import matplotlib.pyplot as plt
sin_x = torch.linspace(-2*math.pi, 2*math.pi, 100) # -2πから2πまで
sin_y = torch.sin(sin_x) + 0.1*torch.randn(len(sin_x)) # sin関数に乱数でノイズを加える
plt.plot(sin_x, sin_y)
plt.show()
その2
from torch.utils.data import TensorDataset, DataLoader
n_time = 10 # 時刻の数
n_sample = len(sin_x)-n_time # サンプル数
input_data = torch.zeros((n_sample, n_time, 1)) # 入力
correct_data = torch.zeros((n_sample, 1)) # 正解
for i in range(n_sample):
input_data[i] = sin_y[i:i+n_time].view(-1, 1) # (時刻の数, 入力の数)
correct_data[i] = sin_y[i+n_time:i+n_time+1] # 正解は入力よりも1つ後
dataset = TensorDataset(input_data, correct_data) # データセットの作成
train_loader = DataLoader(dataset, batch_size=8, shuffle=True) # DataLoaderの設定
その3
import torch.nn as nn
class Net(nn.Module):
def __init__(self):
super().__init__()
self.rnn = nn.RNN( # RNN層
input_size=1, # 入力数
hidden_size=64, # ニューロン数
batch_first=True, # 入力の形状を (バッチサイズ, 時刻の数, 入力の数) にする
)
self.fc = nn.Linear(64, 1) # 全結合層
def forward(self, x):
# y_rnn:全時刻の出力 h:中間層の最終時刻の値
y_rnn, h = self.rnn(x, None)
y = self.fc(y_rnn[:, -1, :]) # -1で最後の時刻のみ取得して全結合層へ渡す
return y
net = Net()
print(net)
その4
from torch import optim
# 平均二乗誤差
loss_fnc = nn.MSELoss()
# 最適化アルゴリズム
optimizer = optim.SGD(net.parameters(), lr=0.01) # 学習率は0.01
# 損失のログ
record_loss_train = []
# 学習
epochs = 100 # エポック数
for i in range(epochs):
net.train() # 訓練モード
loss_train = 0
for j, (x, t) in enumerate(train_loader): # ミニバッチ(x, t)を取り出す
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)
# 経過の表示
if i%10==0 or i==epochs-1:
net.eval() # 評価モード
print("Epoch:", i, "Loss_Train:", loss_train)
predicted = list(input_data[0].view(-1)) # 最初の入力
for i in range(n_sample):
x = torch.tensor(predicted[-n_time:]) # 直近の時系列を取り出す
x = x.view(1, n_time, 1) # (バッチサイズ, 時刻の数, 入力の数)
y = net(x)
predicted.append(y[0].item()) # 予測結果をpredictedに追加する
plt.plot(range(len(sin_y)), sin_y, label="Correct")
plt.plot(range(len(predicted)), predicted, label="Predicted")
plt.legend()
plt.show()
その5
plt.plot(range(len(record_loss_train)), record_loss_train, label="Train")
plt.legend()
plt.xlabel("Epochs")
plt.ylabel("Error")
plt.show()
RNNによる画像生成
その6
from torchvision.datasets import FashionMNIST
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
fmnist_data = FashionMNIST(root="./data",
train=True,download=True,
transform=transforms.ToTensor())
fmnist_classes = ["T-shirt/top", "Trouser", "Pullover", "Dress", "Coat",
"Sandal", "Shirt", "Sneaker", "Bag", "Ankle boot"]
print("データの数:", len(fmnist_data))
n_image = 25 # 表示する画像の数
fmnist_loader = DataLoader(fmnist_data, batch_size=n_image, shuffle=True)
dataiter = iter(fmnist_loader) # イテレータ
images, labels = next(dataiter) # 最初のバッチを取り出す
img_size = 28
plt.figure(figsize=(10,10)) # 画像の表示サイズ
for i in range(n_image):
ax = plt.subplot(5,5,i+1)
ax.imshow(images[i].view(img_size, img_size), cmap="Greys_r")
label = fmnist_classes[labels[i]]
ax.set_title(label)
ax.get_xaxis().set_visible(False) # 軸を非表示に
ax.get_yaxis().set_visible(False)
plt.show()
その7
import torch
from torch.utils.data import TensorDataset
n_time = 14 # 時刻の数
n_in = img_size # 入力層のニューロン数
n_mid = 256 # 中間層のニューロン数
n_out = img_size # 出力層のニューロン数
n_sample_in_img = img_size - n_time # 1枚の画像中のサンプル数
dataloader = DataLoader(fmnist_data, batch_size=len(fmnist_data), shuffle=False)
dataiter = iter(dataloader) # イテレータ
train_imgs, labels = next(dataiter) # データを取り出す
train_imgs = train_imgs.view(-1, img_size, img_size)
n_sample = len(train_imgs) * n_sample_in_img # サンプル数
input_data = torch.zeros((n_sample, n_time, n_in)) # 入力
correct_data = torch.zeros((n_sample, n_out)) # 正解
for i in range(len(train_imgs)):
for j in range(n_sample_in_img):
sample_id = i*n_sample_in_img + j
input_data[sample_id] = train_imgs[i, j:j+n_time]
correct_data[sample_id] = train_imgs[i, j+n_time]
dataset = TensorDataset(input_data, correct_data) # データセットの作成
train_loader = DataLoader(dataset, batch_size=128, shuffle=True) # DataLoaderの設定
その8
n_disp = 10 # 生成し表示する画像の数
disp_data = FashionMNIST(root="./data",
train=False,download=True,
transform=transforms.ToTensor())
disp_loader = DataLoader(disp_data, batch_size=n_disp, shuffle=False)
dataiter = iter(disp_loader) # イテレータ
disp_imgs, labels = next(dataiter) # データを取り出す
disp_imgs = disp_imgs.view(-1, img_size, img_size)
その9
import torch.nn as nn
class Net(nn.Module):
def __init__(self):
super().__init__()
self.rnn = nn.LSTM( # LSTM層
input_size=n_in, # 入力サイズ
hidden_size=n_mid, # ニューロン数
batch_first=True, # 入力を (バッチサイズ, 時刻の数, 入力の数) にする
)
self.fc = nn.Linear(n_mid, n_out) # 全結合層
def forward(self, x):
# y_rnn:全時刻の出力 h:中間層の最終時刻の値 c:記憶セル
y_rnn, (h, c) = self.rnn(x, None)
y = self.fc(y_rnn[:, -1, :]) # yは最後の時刻の出力
return y
net = Net()
net.cuda() # GPU対応
print(net)
その10
def generate_images():
# オリジナルの画像
print("Original:")
plt.figure(figsize=(20, 2))
for i in range(n_disp):
ax = plt.subplot(1, n_disp, i+1)
ax.imshow(disp_imgs[i], cmap="Greys_r", vmin=0.0, vmax=1.0)
ax.get_xaxis().set_visible(False) # 軸を非表示に
ax.get_yaxis().set_visible(False)
plt.show()
# 下半分をRNNにより生成した画像
print("Generated:")
net.eval() # 評価モード
gen_imgs = disp_imgs.clone()
plt.figure(figsize=(20, 2))
for i in range(n_disp):
for j in range(n_sample_in_img):
x = gen_imgs[i, j:j+n_time].view(1, n_time, img_size)
x = x.cuda() # GPU対応
gen_imgs[i, j+n_time] = net(x)[0]
ax = plt.subplot(1, n_disp, i+1)
ax.imshow(gen_imgs[i].detach(), cmap="Greys_r", vmin=0.0, vmax=1.0)
ax.get_xaxis().set_visible(False) # 軸を非表示に
ax.get_yaxis().set_visible(False)
plt.show()
その11
from torch import optim
# 平均二乗誤差
loss_fnc = nn.MSELoss()
# 最適化アルゴリズム
optimizer = optim.Adam(net.parameters())
# 損失のログ
record_loss_train = []
# 学習
epochs = 30 # エポック数
for i in range(epochs):
net.train() # 訓練モード
loss_train = 0
for j, (x, t) in enumerate(train_loader): # ミニバッチ(x, t)を取り出す
x, t = x.cuda(), t.cuda() # GPU対応
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)
if i%5==0 or i==epochs-1:
print("Epoch:", i, "Loss_Train:", loss_train)
generate_images()
その12
plt.plot(range(len(record_loss_train)), record_loss_train, label="Train")
plt.legend()
plt.xlabel("Epochs")
plt.ylabel("Error")
plt.show()