PytorchのTensorを試してみる
PytorchのTensorを試してみる
torch.empty()
>>> x = torch.empty(5,5)
>>> x
tensor([[ 0.0000e+00, 0.0000e+00, 1.2111e-37, 1.4013e-45, -2.1667e+20],
[ 4.5779e-41, -2.1667e+20, 4.5779e-41, -2.1668e+20, 4.5779e-41],
[ 5.9737e-07, 6.4104e-10, 1.3567e-19, 6.4094e-10, 1.4585e-19],
[ 6.4899e-07, 2.5038e-12, 4.1638e-11, 6.4097e-10, 9.3319e-40],
[ 1.4013e-45, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00]])
torch.rand()
>>> x = torch.rand(5,5)
>>> x
tensor([[0.9336, 0.5033, 0.3661, 0.8221, 0.9486],
[0.5814, 0.9131, 0.1426, 0.1064, 0.5611],
[0.9195, 0.7638, 0.8882, 0.8382, 0.1704],
[0.5920, 0.3543, 0.7149, 0.0117, 0.4379],
[0.7179, 0.5070, 0.2185, 0.8193, 0.3506]])
torch.zeros()
>>> x = torch.zeros(5,5)
>>> x
tensor([[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]])
torch.tensor([])
>>> x = torch.tensor([1.1, 2.2, 3.3, 4.4, 5.5]) >>> x tensor([1.1000, 2.2000, 3.3000, 4.4000, 5.5000])
new_ones()
>>> x = x.new_ones(5,5)
>>> x
tensor([[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.]])
dtype(データタイプの指定)
>>> x = torch.rand(5, 5 ,dtype=torch.double)
>>> x
tensor([[0.9080, 0.8823, 0.4970, 0.5745, 0.2689],
[0.7482, 0.8182, 0.7628, 0.5347, 0.9337],
[0.0443, 0.5242, 0.8650, 0.5006, 0.6526],
[0.1058, 0.1484, 0.8282, 0.5445, 0.9101],
[0.9393, 0.4800, 0.7741, 0.8051, 0.0800]], dtype=torch.float64)
shape, size() (tensorのサイズを取得)
>>> x = torch.rand(5,3) >>> x.shape torch.Size([5, 3]) >>> x.size() torch.Size([5, 3]) >>> x.size(0) 5 >>> x.size(1) 3
演算
>>> x = torch.rand(3,3)
>>> y = torch.rand(3,3)
>>> x
tensor([[0.4449, 0.2112, 0.6244],
[0.5940, 0.6442, 0.0575],
[0.4617, 0.6969, 0.9881]])
>>> y
tensor([[0.2623, 0.3369, 0.9841],
[0.8398, 0.8506, 0.4659],
[0.5126, 0.6361, 0.9784]])
>>> torch.add(x,y)
tensor([[0.7072, 0.5481, 1.6085],
[1.4338, 1.4948, 0.5233],
[0.9743, 1.3329, 1.9665]])
>>> x + y
tensor([[0.7072, 0.5481, 1.6085],
[1.4338, 1.4948, 0.5233],
[0.9743, 1.3329, 1.9665]])
演算(出力先を指定)
>>> x = torch.rand(3,3)
>>> y = torch.rand(3,3)
>>> result = torch.empty(3,3)
>>> torch.add(x, y, out=result)
tensor([[0.4299, 1.6843, 1.1674],
[1.6310, 1.2367, 1.2494],
[0.8625, 0.9575, 1.4197]])
スライシング
>>> x = torch.rand(5,5)
>>> x
tensor([[0.8801, 0.0515, 0.8298, 0.0895, 0.2612],
[0.2635, 0.1787, 0.7860, 0.2423, 0.9221],
[0.7556, 0.4374, 0.7314, 0.6534, 0.4783],
[0.9463, 0.7781, 0.0977, 0.1606, 0.2483],
[0.1573, 0.9691, 0.6578, 0.9738, 0.9746]])
>>> x[:, 1]
tensor([0.0515, 0.1787, 0.4374, 0.7781, 0.9691])
変換(行列 -> ベクトル、ベクトル -> 行列)
>>> x = torch.rand(4,4)
>>> x
tensor([[0.0995, 0.0718, 0.3917, 0.5440],
[0.9479, 0.1995, 0.3759, 0.1117],
[0.1568, 0.4121, 0.2951, 0.3687],
[0.0139, 0.3464, 0.4001, 0.7129]])
>>> y = x.view(16) # 要素数16のベクトルに変換
>>> y
tensor([0.0995, 0.0718, 0.3917, 0.5440, 0.9479, 0.1995, 0.3759, 0.1117, 0.1568,
0.4121, 0.2951, 0.3687, 0.0139, 0.3464, 0.4001, 0.7129])
>>> z = x.view(-1, 8) # 要素数8のベクトル(2つ)に変換
>>> z
tensor([[0.0995, 0.0718, 0.3917, 0.5440, 0.9479, 0.1995, 0.3759, 0.1117],
[0.1568, 0.4121, 0.2951, 0.3687, 0.0139, 0.3464, 0.4001, 0.7129]])
tensorから値を取り出す
ただし、item()は要素数1のtensorしか実行できない。
>>> x = torch.rand(1) >>> x tensor([0.0833]) >>> x.item() 0.08332055807113647
torch tensorからnumpy arrayに変換
>>> a = torch.ones(5) >>> a tensor([1., 1., 1., 1., 1.]) >>> b = a.numpy() # numpy arrayに変換(参照渡し) >>> b array([1., 1., 1., 1., 1.], dtype=float32) >>> a.add_(1) tensor([2., 2., 2., 2., 2.]) >>> b # 参照渡しなので値が更新される array([2., 2., 2., 2., 2.], dtype=float32)
numpy arrayからtorhc tensorに変換
>>> a = np.ones(5) >>> a array([1., 1., 1., 1., 1.]) >>> b = torch.from_numpy(a) >>> b tensor([1., 1., 1., 1., 1.], dtype=torch.float64) >>> np.add(a, 1, out=a) array([2., 2., 2., 2., 2.]) >>> b tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
Pytorchでの学習済みモデルの保存と読み込み
モデルの保存
params = net.state_dict() #netはモデル名 torch.save(params, "ファイル名.prm", pickle_protocol=4)
モデルの読み込み
params = torch.load("ファイル名.prm", map_location="cpu")
net.load_state_dict(params)
PytorchでCNN(画像分類)を書いてみる。
PytorchでCNN(画像分類)を書いてみる。
以下を参考にCIFAR10 datasetを用いたCNNを書いてみる。
pytorch.org
ソースコード
import torch
import torchvision
import torchvision.transforms as transforms
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchsummary import summary
import matplotlib.pyplot as plt
import numpy as np
# 学習回数
EPOCH = 4
PATH = 'データセットを保存するディレクトリ'
# 前処理の定義と正規化
transform = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))])
# トレーニング用データセットのダウンロードと前処理
# 引数
# root : データセットを保存するディレクトリ。
# train : トレーニング用のデータを取得するかどうかを選択。
# download:参照したディレクトリにDatasetがない場合ダウンロードするかどうかを決める。
# transform:定義した前処理を渡す。これにより、Dataset内のdataを参照する際にその前処理を自動で行ってくれる。
trainset = torchvision.datasets.CIFAR10(root=PATH, train=True,download=True, transform=transform)
# トレーニング用のDataloaderの作成
# 引数
# 第1引数は先程取得したDatasetを入れる
# batch_size:1回のtrainingまたはtest時にまとめて何個のdataを使用するかを選択。(datasetの全data数を割り切れる値にしなければならない)
# shuffle:dataの参照の仕方をランダムにする。
# num_workers:並列処理を行う。2以上の場合はその数だけ並列処理を行う。
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=2)
# テスト用のデータセットのダウンロードと前処理
testset = torchvision.datasets.CIFAR10(root=PATH, train=False, download=True, transform=transform)
# テスト用のDataloaderの作成
testloader = torch.utils.data.DataLoader(testset, batch_size=4, shuffle=False, num_workers=2)
### ネットワーク(CNN)の定義 ###
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 6, 5) # nn.Conv2d(input, output, kernel_size)
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(6, 16, 5)
self.fc1 = nn.Linear(16*5*5, 120) # nn.Linear(input, output)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 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 = F.relu(self.fc2(x))
x = self.fc3(x)
return x
# ネットワークのインスタンス化
net = Net()
# loss関数の定義
criterion = nn.CrossEntropyLoss()
# 最適化関数の定義
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
### トレーニング ###
for epoch in range(EPOCH):
running_loss = 0.0
for i, data in enumerate(trainloader, 0):
# データ[input, labels]を取得
inputs, labels = data
# 均配の初期化
optimizer.zero_grad()
#フォワード処理forward関数の実行)
outputs = net(inputs)
# lossを計算
loss = criterion(outputs, labels)
# lossから均配を計算
loss.backward()
# 最適化(均配からパラメータの更新)
optimizer.step()
# 学習過程を表示
running_loss += loss.item()
if i % 2000 == 1999: # print every 2000 mini-batches
print('[%d, %5d] loss: %.3f' %
(epoch + 1, i + 1, running_loss / 2000))
running_loss = 0.0
# 次回から学習しなくていいように、学習済みモデルのパラメータを"net_00.prmとして保存"
params = net.state_dict()
torch.save(params, "net_00.prm", pickle_protocol=4)
print('Finished Training')
### 学習済みモデルのテスト ###
correct = 0
total = 0
with torch.no_grad(): # パラメータ保持の停止(test時には必要ないので。)
for data in testloader:
images, labels = data
# 各ラベルの確率がoutputに出力される
outputs = net(images)
# torch.maxは最大値とそのインデックス(ラベル)を返す
# 最大値は無視してラベルのみを保存
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
# 正解率を出力
print('Accuracy of the network on the 10000 test images: %d %%' %
(100 * correct / total))
実行結果
Accuracy of the network on the 10000 test images: 56 %
bcm2835-clk fe101000.cprman: plla: couldn't lock PLL[解決方法を追記]
Raspberry pi 4をアップグレード(カーネル:2020/02/10)したら起動しなくなった。。。
調べてみると、Raspbian Buster(2020-02-05)で再インストールすると起動するみたい。
できれば、バグが改善されて、再インストールせずにちゃんと起動してくれるといいんだけど。。。
詳細は以下。
raspida.com
解決方法
以下で紹介されている修正ファイルを使ったら無事起動した。
raspida.com
我が家にRaspberry-pi 4がやってきた!
Raspberry-pi 4を購入した。
ずっとRaspberry-pi 2を使っていたので、それに比べたらすごく快適に動作する。
TensorFlowやPyTorchなどでディープラーニングを試せるといいな。



Raspberry Pi 4にPyTorchをインストールする。
Raspberry Pi4に機械学習ライブラリPyTorchをインストールしてみる。
手順
パッケージのアップデート
$ sudo apt-get update $ sudo apt-get upgrade
2Gのswap領域を作成する。
PyTorchのビルドにはメモリを大量に使用するので、そのために2Gのswap領域を用意する。
$ sudo dd if=/dev/zero of=/swap1 bs=1M count=2048 #2GBのSWAPファイルを作成 $ sudo mkswap /swap1 # 空のスワップ対応ファイルを作成
次に、古いスワップスペースを無効にし、新しいスワップスペースを有効にするために、"/etc/fstab"を開き、以下の記述をファイルを最後に追記する。
("/swap0 swap swap"の記述がある場合はそれを以下に変更する。)
/swap1 swap swap
以下のコマンド(or システムの再起動)で設定を反映する。
$ sudo swapoff /swap0 $ sudo swapon /swap1
必要なパッケージをインストール
$ sudo apt-get -y install cython3 m4 $ sudo apt-get -y install libblas-dev libopenblas-dev $ sudo apt-get -y install libatlas-dev libatlas-base-dev $ sudo apt-get -y install python3-dev python3-yaml python3-cffi
PyTorchをgit cloneしてパッチをあてる。
$ git clone https://github.com/pytorch/pytorch --depth 1 --recursive $ git submodule update --remote third_party/protobuf $ cd pytorch
PyTorchをビルドする時の環境変数を設定する
$ export NO_CUDA=1 $ export NO_DISTRIBUTED=1 $ export NO_MKLDNN=1 $ export BUILD_TEST=0 $ export MAX_JOBS=4 # MAX_JOBSはビルド時に稼働させるプロセッサコア数
ビルド
(python3のバージョンは3.7.3を使用した。)
$ python3 setup.py build
他のRaspberry Piにインストールするためにpipパッケージを作成
$ python3 setup.py bdist_wheel
pipよりPyTorchをインストール
$ cd dist $ pip3 install torch-1.5.0a0+e2f1288-cp37-cp37m-linux_armv7l.whl
torchvisionのインストール
ついでにPyTorchのパッケージであるtorchvisionをインストールしておく。
$ pip3 install torchvision
RaspberryPiにpyenvをインストールしてpython3の環境を構築する。
RaspberryPiにpyenvをインストールしてpython3の環境を構築する。
pyenvのインストール
必要なパッケージのインストール
$ sudo apt-get install -y git openssl libssl-dev libbz2-dev libreadline-dev libsqlite3-dev
pyenvをgit cloneする
$ git clone https://github.com/yyuu/pyenv.git ~/.pyenv
pyenvのPATHを設定する
以下を$HOME/.bashrcに追記する。
export PYENV_ROOT="$HOME/.pyenv" export PATH="$PYENV_ROOT/bin:$PATH" eval "$(pyenv init -)"
これでpyenvのインストールは完了。
pyenvを使ってpython3環境を構築する。
python3をインストールする。
以下のコマンドでインストールできるpythonのバージョンを確認する。
$ pyenv install --list
以下のコマンドより好みのpythonのバージョンをインストールする。
(ここではバージョン3.8.0をインストールする。)
$ pyenv install 3.8.0
pythonのバージョンを切り替える
以下のコマンドよりインストールしたpythonのバージョンに切り替える。
$ pyenv global 3.8.0
バージョンが切り替わっているか確認
$ python -V Python 3.8.0
元のpythonのバージョンに戻したい場合は以下のコマンドを実行する。
$ pyenv global system