k0b0's record.

Computer Engineering, Arts and Books

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で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などでディープラーニングを試せるといいな。

f:id:k0b0:20200210090416j:plain

f:id:k0b0:20200210090444j:plain

f:id:k0b0:20200210090508j:plain

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