趣味、研究、その他いろいろ

投稿者: itotaku

突然nginxが404 Not Foundになった件

起きた問題

私は自宅にWebサーバーを立ててブログサイトを建設しているのですが、ある日突然、「404 Not Found」となり、表示されなくなってしまいました。

systemctl restartしても変わりませんでした。

色々調べた結果

調べても、/etc/nginx/conf.d/配下にあるconfigファイルをいじる等の解決策は出てきましたが、私の場合は解決しませんでした。

解決方法

私の場合、一緒に動いているphp7.4-fpmの権限が原因でした。

$ sudo chmod 666 /run/php/php7.4-fpm.sock

と666にすることで直りました!

私のtmux.conf紹介

set -g default-terminal "screen-256color"
set -g terminal-overrides 'xterm:colors=256'

set -s escape-time 0

set-option -g status-interval 1

set -g base-index 1

setw -g pane-base-index 1

#set -g window-style 'bg=colour239'
#set -g window-active-style 'bg=colour234'

set -g prefix C-x

#bind - split-window -v

#bind \ split-window -h
bind-key \\ split-window -h
bind-key - split-window -v
# ペインの縦分割
#bind m split-window -vc "#{pane_current_path}"
# ペインの横分割
#bind n split-window -hc "#{pane_current_path}"

bind -n S-left select-pane -L
bind -n S-down select-pane -D
bind -n S-up select-pane -U
bind -n S-right select-pane -R

# Shift arrow to switch windows
bind -n C-Left  previous-window
bind -n C-Right next-window

bind -n C-o select-pane -t :.+

bind e setw synchronize-panes \; display "synchronize-panes #{?pane_synchronized,on,off}"

# Prefix+v でコピーモード開始
bind-key v copy-mode \; display "Copy mode!"
#bind-key -t vi-copy v begin-selection

# Prefix+p でペースト
# クリップボードにも保存されているので Cmd-v でもペースト可能
bind-key p paste-buffer

set-option -g status-justify "centre"

set-option -g status-bg "colour238"

set-option -g status-fg "colour255"

set-option -g status-left-length 20

set-option -g status-left "#[fg=colour255,bg=colour241]Session: #S #[default]"

set-window-option -g window-status-format " #I: #W "

set-window-option -g window-status-current-format "#[fg=colour255,bg=colour27,bold] #I: #W #[default]"

set-option -g status-right-length 60

set-option -g status-right "#[fg=colour255,bg=colour241] #h | LA: #(cut -d' ' -f-3 /proc/loadavg) | %m/%d %H:%M:%S#[default]"

set-option -g mouse on

bind -n WheelUpPane   select-pane -t= \; copy-mode -e \; send-keys -M
bind -n WheelDownPane select-pane -t= \;                 send-keys -M
#set-window-option -g mode-mouse on
#set-option -g mouse-select-window on
#set-option -g mouse-resize-pane on
#set-option -g mouse-select-pane on

cronが正しく送られない話

やりたいこと

Line Notifyを用いて定期的にリマインドしてくれるようにしたい

手順

Line Notifyのページ(こちら)からログインしてアクセストークンの発行(開発者向け)を行う。

Line notifyで通知してくれるシェルスクリプトを作成

自分は以下のように書きました。(リマインド:炊飯と通知してくれるコードです)

#!/bin/bash
LINE_ACCESS_TOKEN="jXN4lE38ve0ljxYRlF9jPBwytvcI48Xsad1iqRBKTeF"
function line_notify() {
  MESSAGE=$1
  curl -X POST -H "Authorization: Bearer ${LINE_ACCESS_TOKEN}" -F "message=$MESSAGE" https://notify-api.line.me/api/notify
}
line_notify "リマインド:炊飯"

これをcronに登録

$ echo "0 17 * * * . /home/itotaku/cron/notify_rice.sh" > cron.conf
$ crontab cron.conf

どこで詰まったか

直接

. /home/itotaku/cron/notify_rice.sh

とすれば通知できるのにcronを経由すると通知が来なかった。

Web検索しながら調べてみた

Webサイトで解決策を調べてみると、postfixのインストールが必要という記事をよく見ました。

それの通りにやってもうまくいかなかったです。

結局どう解決したか

根本的な問題の解決には至っていないかもしれませんが、シェルスクリプトに実行権限を与え、ドットコマンド(.)を使わずに登録すればうまくいきました。

$ chmod 775 notify_rice.sh
$ echo "0 17 * * * /home/itotaku/cron/notify_rice.sh" > cron.conf
$ crontab cron.conf

通知が来た!

let’s encriptの証明書の有効期限が切れたときの対処方法について

環境

Ubuntu20.04

nginx version: nginx/1.18.0 (Ubuntu)
built with OpenSSL 1.1.1f 31 Mar 2020

問題

let’s encriptのSSL証明書は3ヶ月であり、期限が切れてしまっていた。

有効期限が切れてしまうと

$ sudo certbot renew

をしてもうまくいかない。

解決策

有効期限が切れてしまった場合はまた1から証明書を作成する必要がある。

$ sudo certbot --nginx -d {ドメイン名}

と入力する。私のサイトでは

$ sudo certbot --nginx -d tsubame.0am.jp

となる。

証明書を作成したのに保護されない場合

良くある原因

まず良くある原因としてはnginxの設定ファイルで証明書のパスの指定が記述されていないことです。

設定ファイルの記述は/etc/nginx/conf.d/ssl.confに行います。

server {
    listen 443 ssl;
    server_name  tsubame.0am.jp www.tsubame.0am.jp;

    location / {
        root   /usr/share/nginx/html;
        index  index.php index.html index.htm;
    }

    ssl_certificate /etc/letsencrypt/live/tsubame.0am.jp/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/tsubame.0am.jp/privkey.pem;

    error_page  404  https://tsubame.0am.jp;

    error_page 500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    location ~ \.php$ {
        try_files $uri =404;
        root           /usr/share/nginx/html;
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_script_name;
        include fastcgi_params;
    }
    location ^~ /index.html {
      return 301 http://tsubame.0am.jp/itotakublog/index.php$query_string;
    }
}

server {
    # httpをhttpsにリダイレクト
    listen 80;
    return 301 https://$host$request_uri;
}
server {
    listen 443 ssl;
    # SSLを無効化してTLSのみ受け付ける
    ssl_protocols  TLSv1.2 TLSv1.3;
}

私の場合

私のサイトではURLが間違っていた場合、全てホームページにリダイレクトするようにしているのですが、その時に80ポートもリッスンしているとhttpの方にリダイレクトされてしまうことがあるみたいです。

よって/etc/nginx/conf.d/ssl.conf

listen 80

をコメントアウトすることで解決できました。

Pytorchを用いたCNNサンプルコード

# -*- coding: utf-8 -*-
import sys, os
import torch
import numpy as np
import torch.nn.functional as F
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
from torch.utils.data.sampler import SubsetRandomSampler
import matplotlib.pyplot as plt
import torch.nn as nn
import time
from tqdm import tqdm
MODEL_PATH = "CNNmodel.pth.tar"
MODEL_SAVE_PATH = "CNNmodel_normal.pth.tar"

def load_cifar10(batch=128):
    num_workers = 4
    valid_size = 0.2
    train_data = datasets.MNIST(root = 'data', train = True, download = True, transform = transforms.Compose([ transforms.ToTensor()]))
    test_data = datasets.MNIST(root = 'data', train = False, download = True, transform = transforms.Compose([ transforms.ToTensor()]))

    num_train = len(train_data)
    indices = list(range(num_train))
    np.random.shuffle(indices)
    # trainとvalidの境目(split)を指定
    split = int(np.floor(valid_size * num_train))
    train_index, valid_index = indices[split:], indices[:split]

    # samplerの準備
    train_sampler = SubsetRandomSampler(train_index)
    valid_sampler = SubsetRandomSampler(valid_index)
    # data loaderの準備
    train_loader = torch.utils.data.DataLoader(train_data, batch_size = batch,
                                               sampler = train_sampler, num_workers = num_workers)
    valid_loader = torch.utils.data.DataLoader(train_data, batch_size = batch,
                                              sampler = valid_sampler, num_workers = num_workers)
    test_loader = torch.utils.data.DataLoader(test_data, batch_size = batch,
                                             num_workers = num_workers)

    return {'train_loader': train_loader, 'valid_loader': valid_loader, 'test_loader': test_loader}

class MyCNN(torch.nn.Module):
    def __init__(self):
        super(MyCNN, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, 5)  # 28x28x1 -> 24x24x32
        self.pool = nn.MaxPool2d(2, 2)  # 24x24x32 -> 12x12x32
        self.dropout1 = nn.Dropout2d(0.2)
        self.conv2 = nn.Conv2d(32, 64, 5)  # 12x12x32 -> 8x8x64
        self.dropout2 = nn.Dropout2d(0.2)
        self.fc1 = nn.Linear(8 * 8 * 64, 128)
        self.fc2 = nn.Linear(128, 10)

    def forward(self, x):  # predictに相当(順伝搬)
        x = self.pool(F.relu(self.conv1(x)))
        x = F.relu(self.conv2(x))
        x = self.dropout1(x)
        x = x.view(-1, 8 * 8 * 64)
        x = F.relu(self.fc1(x))
        x = self.dropout2(x)
        x = self.fc2(x)
        return x

def save_checkpoint(state, filename):
    torch.save(state, filename)

def train():
    print("will begin training")
    flag_70=False
    flag_99=False
    for ep in range(epoch):
        train_loss_total = 0
        train_acc_total = 0
        valid_loss_total = 0
        valid_acc_total = 0
        net.train()
        loss = None
        for i, (images, labels) in enumerate(loader['train_loader']):
            # viewで28×28×1画像を1次元に変換し、deviceへ転送
            images, labels = images.to(device), labels.to(device) # そのまま使う
            optimizer.zero_grad()  # 勾配リセット
            outputs = net(images)  # 順伝播の計算
            loss = criterion(outputs, labels)  # lossの計算
            train_loss_total += loss.item()  # train_loss に結果を蓄積
            acc = (outputs.max(1)[1] == labels).sum()  # 予測とラベルが合っている数の合計
            train_acc_total += acc.item()  # train_acc に結果を蓄積
            loss.backward()  # 逆伝播の計算
            optimizer.step()  # 重みの更新
            if i % 10 == 0:
                print('Training log: {} epoch ({} / 50000 train. data). Loss: {}, Acc: {}'.format(ep + 1,
                                                                                         (i + 1) * 128,
                                                                                         loss.item(),
                                                                                         acc)
                      )

        torch.save(net.state_dict(), MODEL_SAVE_PATH)
        train_loss = train_loss_total / len(loader['train_loader'].sampler)
        train_acc = train_acc_total / len(loader['train_loader'].sampler)

        history['train_loss'].append(train_loss)
        history['train_acc'].append(train_acc)

        net.eval()
        correct = 0
        with torch.no_grad():
            for i, (images, labels) in enumerate(tqdm(loader['valid_loader'])):
                # viewで28×28×1画像を1次元に変換し、deviceへ転送
                images, labels = images.to(device), labels.to(device)  # そのまま使う
                outputs = net(images) # 出力を計算(順伝搬)
                loss = criterion(outputs, labels) # lossを計算
                valid_loss_total += loss.item() # lossを足す
                acc = (outputs.max(1)[1] == labels).sum() # 正解のものを足し合わせてaccを計算
                valid_acc_total += acc.item() # accを足す

        valid_loss = valid_loss_total / len(loader['valid_loader'].sampler)
        valid_acc = valid_acc_total / len(loader['valid_loader'].sampler)
        history['valid_loss'].append(valid_loss)
        history['valid_acc'].append(valid_acc)
        print("valid_acc=",valid_acc)
        if valid_acc>=0.7 and flag_70==False:
            print("70%over")
            flag_70=True
            torch.save(net.state_dict(), 'CNNmodel_checkpoint_70.pth.tar')
        elif valid_acc>=0.99 and flag_99==False:
            print("99%over")
            flag_99=True
            torch.save(net.state_dict(), "CNNmodel_checkpoint_99.pth.tar")

def test():
    test_loss_total = 0
    test_acc_total = 0
    total = 0
    class_correct = list(0. for i in range(10))
    class_total = list(0. for i in range(10))
    net.eval() # ネットワークを推論モードへ
    with torch.no_grad():
        for i, (images, labels) in enumerate(tqdm(loader['test_loader'])):
            images, labels = images.to(device), labels.to(device)
            outputs = net(images)
            loss = criterion(outputs,labels) # 損失を計算
            # 出力と結果が一致している個数を計算
            _,pred = torch.max(outputs,1)
            test_acc_total += np.squeeze(pred.eq(labels.data.view_as(pred)).sum())
            total += labels.size(0)
            test_loss_total += loss.item()*images.size(0)
            c = (pred == labels).squeeze()
            for i in range(4):
                label = labels[i]
                class_correct[label] += c[i]
                class_total[label] += 1

    test_loss = test_loss_total / len(loader['test_loader'].sampler)
    test_acc = test_acc_total.item() / len(loader['test_loader'].sampler)
    history['test_loss'].append(test_loss)
    history['test_acc'].append(test_acc)

    print('Accuracy of the network on the 10000 test images: %d %%' % (
        100 * test_acc_total.item() / total))
    for i in range(10):
        print('Accuracy of %5s : %2d %%' % (
            classes[i], 100 * class_correct[i] / class_total[i]))

def plot():
    # 結果をプロット
    plt.figure()
    plt.plot(range(1, epoch+1), history['train_loss'], label='train_loss', color='red')
    plt.plot(range(1, epoch+1), history['valid_loss'], label='val_loss', color='blue')
    plt.title('CNN Training Loss [CIFAR10]')
    plt.xlabel('epoch')
    plt.ylabel('loss')
    plt.legend()
    plt.savefig('img/CNN_loss.png')

    plt.figure()
    plt.plot(range(1, epoch+1), history['train_acc'], label='train_acc', color='red')
    plt.plot(range(1, epoch+1), history['valid_acc'], label='val_acc', color='blue')
    plt.title('CNN Accuracies [CIFAR10]')
    plt.xlabel('epoch')
    plt.ylabel('accuracy')
    plt.legend()
    plt.savefig('img/CNN_acc.png')
    plt.close()

if __name__ == '__main__':
    start = time.time()
    epoch = 10
    loader = load_cifar10()
    classes = ('plane', 'car', 'bird', 'cat', 'deer',
               'dog', 'frog', 'horse', 'ship', 'truck')  # CIFAR10のクラス
    torch.backends.cudnn.benchmark=True
    use_cuda=torch.cuda.is_available()
    if use_cuda:
        device = 'cuda'
    else:
        device = 'cpu'
    print("device=",device)
    net: MyCNN = MyCNN().to(device)
    criterion = torch.nn.CrossEntropyLoss()  # ロスの計算
    optimizer = torch.optim.SGD(params=net.parameters(), lr=0.01, momentum=0.9,weight_decay=0.00005)
    flag = os.path.exists(MODEL_PATH)
    if flag: #前回の続きから学習
        print('loading parameters...')
        source = torch.load(MODEL_PATH, map_location=lambda storage, loc: storage)
        net.load_state_dict(source)
        print('parameters loaded')
    else:
        print("途中のパラメータなし")

    history = {
        'train_loss': [],
        'train_acc': [],
        'valid_loss': [],
        'valid_acc': [],
        'test_loss': [],
        'test_acc': []
    }
    train()
    test()
    if flag == False:
        plot()
    elapsed_time = time.time() - start
    print ("elapsed_time:{0}".format(elapsed_time) + "[sec]")
cycler==0.10.0
dataclasses==0.6
future==0.18.2
kiwisolver==1.3.1
matplotlib==3.3.3
numpy==1.19.4
Pillow==8.0.1
pyparsing==2.4.7
python-dateutil==2.8.1
six==1.15.0
torch==1.7.0+cu110
torchaudio==0.7.0
torchvision==0.8.1+cu110
tqdm==4.52.0
typing-extensions==3.7.4.3

SSDの容量が何故か少ない!

今回はSSDの容量が合っていない時の私が直面した問題とその対処法についてご紹介します。

問題の状況

私は1TBのm.2SSDを購入して自作pcに挿入して使っています。

UbuntuにはUbuntu DesktopとUbuntu Serverがあります。

Ubuntu Desktopは普通に自作pcをパソコンとして使いたい人向け

Ubuntu Serverは自作pcをサーバーとして使いたい人向けです。

ちなみにServerとDesktop両方入れることもでき、その場合は最初にServerを入れてからDesktopを入れた方が遙かに楽だと思います。

無知な私はServerを入れたいのに間違ってDesktopを入れてしまいました。(これを間違えなかったら以下の問題は発生しなかったかもしれません。)

その後Ubuntu Serverを再度インストールしてServer内で

df -h

コマンドで見ると

Filesystem                         Size  Used Avail Use% Mounted on
udev                                16G     0   16G   0% /dev
tmpfs                              3.2G  2.1M  3.2G   1% /run
/dev/mapper/ubuntu--vg-ubuntu--lv  196G   36G  151G  20% /
tmpfs                               16G     0   16G   0% /dev/shm
tmpfs                              5.0M  4.0K  5.0M   1% /run/lock
tmpfs                               16G     0   16G   0% /sys/fs/cgroup
/dev/nvme0n1p2                     976M  244M  665M  27% /boot
/dev/nvme0n1p1                     511M  7.8M  504M   2% /boot/efi
/dev/loop0                          55M   55M     0 100% /snap/core18/1880
/dev/loop1                          56M   56M     0 100% /snap/core18/1932
/dev/loop3                          30M   30M     0 100% /snap/snapd/8542
/dev/loop2                          68M   68M     0 100% /snap/lxd/18150
/dev/loop4                          72M   72M     0 100% /snap/lxd/16099
/dev/loop5                          31M   31M     0 100% /snap/snapd/9721
tmpfs                              3.2G   20K  3.2G   1% /run/user/122
tmpfs                              3.2G   24K  3.2G   1% /run/user/1000

1TBのm.2SSDが196GBしかありません。

解決策の前に一つ

今回直面した問題の解決策を理解するにはLVM(Logical Volume Management)という概念を理解しなければいけません。(知ってるよ!という方は読み飛ばしてください)

今回の問題で使う部分のみ説明を行うと

1Tバイトのある「物理ボリューム」というSSD上のパーティションがあり、これを複数の「論理ボリューム」という仮想のパーティションに分けています。

私の場合はUbuntu Serverに使われていた「論理ボリューム」が196Gバイトしかなかったということになります。(残りの約800Gバイトは別の論理ボリュームに割り当てられているト考えられます。)

m.2SSDの容量を全て使いたい!と思うと思います。

LVMには様々なコマンドがあって上記のことももちろんできます。

以下に私の場合の解決策を提示したいと思います。

解決策

私の場合は「Serverの論理ボリュームを全ての空き容量に拡張して使う」ということです。

論理ボリュームの拡大には「lvextend」コマンド

全ての空き容量を使うには「+100%FREE」オプションを使います。

私の場合は1TBの物理ボリュームが入っているubuntu-vgという物理ボリュームの集まり(ボリュームグループ)があり、

そこに含まれる論理ボリュームを拡張したいので

lvextend -l +100%FREE ubuntu-vg/ubuntu-lv

これで

itotaku@anubis:~$ df -hT
Filesystem                        Type      Size  Used Avail Use% Mounted on
udev                              devtmpfs   16G     0   16G   0% /dev
tmpfs                             tmpfs     3.2G  2.1M  3.2G   1% /run
/dev/mapper/ubuntu--vg-ubuntu--lv ext4      915G   36G  840G   5% /
tmpfs                             tmpfs      16G     0   16G   0% /dev/shm
tmpfs                             tmpfs     5.0M  4.0K  5.0M   1% /run/lock
tmpfs                             tmpfs      16G     0   16G   0% /sys/fs/cgroup
/dev/nvme0n1p2                    ext4      976M  244M  665M  27% /boot
/dev/nvme0n1p1                    vfat      511M  7.8M  504M   2% /boot/efi
/dev/loop0                        squashfs   55M   55M     0 100% /snap/core18/1880
/dev/loop1                        squashfs   72M   72M     0 100% /snap/lxd/16099
/dev/loop2                        squashfs   68M   68M     0 100% /snap/lxd/18150
/dev/loop3                        squashfs   30M   30M     0 100% /snap/snapd/8542
/dev/loop4                        squashfs   56M   56M     0 100% /snap/core18/1932
/dev/loop5                        squashfs   31M   31M     0 100% /snap/snapd/9721
tmpfs                             tmpfs     3.2G   16K  3.2G   1% /run/user/122
tmpfs                             tmpfs     3.2G   24K  3.2G   1% /run/user/1000

915GB(約1T)になってる!

皆さんも

df-h

結果に「~~vg」や「~~lv」等があったらLVMを疑ってみてください!

他にもLVMにはたくさんコマンドがあります。それらは上記のリンクを参照してください。

自作pc初心者だから言えるよくある躓きポイント!

こちらはrioyokotalab Advent Calendar 2020の14日目の記事です

自作pcは一人で始めるにはとても勇気がいることだと思います。幸いにも自分には同じ研究室に自作pcについて知り尽くしているエキスパートがいらっしゃったので助かりました。

今回は自作pcを始めよう!と思った人向けにパーツを購入する段階からpcを組み立て終わる段階までに関して自作pcについての注意点を紹介していきたいと思います!(初めて自作pcをする人は必見です!)

細かく写真を入れてあるのでわかりやすいと思います!

ここで一つ注意点として自分はm.2SSD1つのみをストレージに使っていたのでSATAと呼ばれるケーブルを使っていません。こちらについては書いていないので予めご了承を。

パーツ購入時の注意点

パーツ購入時に注意しなければならないのはお互いのパーツが対応しているかを確かめることです。これを怠るとパーツを購入し直しなんてことになりがちです。

さて、自作pcに必要な部品は、

・CPU

・マザーボード

・メモリ

・GPU(マザーボードにグラフィック機能がついていない場合)

・電源

・SSD

・pcケース

こんな感じです。

部品を決めていく際、自分は上に上げたような順番で探していくのがいいと思います。

自分が部品選択の際、注意すべき点だと思ったことは以下になります。これらを確かめるには価格ドットコムのサイトであれば商品ページに進むと「メーカー製品情報ページ」や「メーカー仕様表」というリンクがあるのでそのリンク先に仕様が全て載っているので確認できます。

・マザーボードがCPU、メモリに対応しているか ← マザーボード選択時

・CPUのメモリータイプがメモリに対応しているか ← メモリ選択時

・CPUのPCIeが電源に対応しているか ← 電源選択時

・電源がGPUの推奨電源、PCIeのピン数に対応しているか ← 電源選択時

・pcケースがマザーボードの大きさに対応しているか(ATX,MicroATX,MiniITX等) ← pcケース選択時

ぐらいだと思います。

自分の場合は深層学習に使うという用途もあったのでGPUもいいものを買いました。(RTX3070という7万円くらいするGPU)

購入に関してはこのくらいにして次は商品が届いて組み立ての段階です!

組み立てるときの注意点

組み立てるとき、自分は本当に何も知らなくていろいろ苦労しました。。。

後々気づいて解体、組み立て…を何回したのか覚えていません。

そんな初心者の方が躓きがちなポイントについて細かく説明していきたいと思います。

CPUの取り付け

まずマザーボードを広げて最初にCPUを取り付けます。

おそらくほとんどのCPUにはCPUクーラーとその底面にグリスというなんか手につくやつも付着しているのでCPUクーラーの底面はできるだけ触らないようにしましょう。

CPUをマザーボードにくっつけます。まずマザーボードのCPU挿入位置の横にある棒

CPU挿入位置の横にある棒

これを外側に引っ張りながら上に上げます。こうすることでCPUを挿入できるようになります。

次にCPUを挿入します。このとき、向きを間違えないようにします。CPUには矢印マークみたいなのがあります。

CPU(AMD Ryzen 5 3600)(引用)
拡大したもの

この矢印をマザーボードの

マザーボード(GIGABYTE B550M S2H マザーボード MicroATX)

ちょっと見にくいですが矢印があるはずです。この2つの矢印が合うように挿入します。

CPUを挿入し終わったら横にあるレバーを元に戻しましょう。

次にCPUクーラーの取り付けです。今取り付けたCPUの周りにこのようなネジがあります。(ない場合もあり、その場合は穴が空いているはず?)

CPUクーラーネジ

これを外します。マザーボードの下につながっていた部品が外れると思います。

この部品とCPUクーラーがくっつくように再度ネジを止めます。ネジはpcケースに付属のネジを使います。

CPUクーラーを取り付けたらCPUクーラーから出ているピンをマザーボードの「CPU_FAN」と書いてあるピンにくっつければCPUの設置は完成です。

CPU_FAN

メモリの取り付け

メモリの取り付け位置は

メモリ

ここですね。自分のマザーボードには2つありますが、1つのマザーボードもあります。こちらは購入時に確認済みかと思います。

この両端あるいは片方にレバーがついていると思うのでこれを押して開いてあげます。

ここにメモリを取り付けますが、思ったより固いです。。。

固いですが、力の加減を知らないとバキッと折れてしまう可能性もなくはないので丁寧に入れていくことが大切です。

メモリは向きが決まっていて短い方と長い方があります。

メモリ(引用)

上の画像だと左の方が長いですね。

この長さをマザーボードと合わせないと一生入りません。

自分がおすすめする入れ方は

この長さを合わせたらやや強めに両端から押してある程度入れます。

その後どちらか一方を強く押して「カチッ」と言う音がしてレバーが戻るまで押し込みます。

その後もう一方を強く押して「カチッ」という音がしてレバーが戻るまで押し込みます。

この時「カチッ」という音がしなかった場合はうまくメモリが挿入できていないのでもう一度やり直してください。

SSDの取り付け

自分はm.2SSDというマザーボードに直接差し込むタイプのSSDを購入したのでそちらの取り付け方法になります。

こちらの挿入位置は

m.2SSDの挿入位置

ここですね。早速取り付け方の説明をしていきます。

まず、黄色く囲ったネジを一度取り外します。このネジはm.2SSDを固定するために使います。

ネジが外れたらm.2SSDを長さが合うように挿入します。挿入後、ネジをm.2SSDの上から止め、固定してあげます。

m.2SSDの取り付けは簡単ですね。

ここまでマザーボードに取り付けたらまだグラボ等をつける必要がありますがこちらはpcケースにマザーボードを取り付けた後行った方が効率的だなと思ったので次はpcケースにマザーボードを取り付けていきます。

pcケースにマザーボードを取り付ける

pcケースの両側のネジを外し中身を開けます。そして空間が大きい方を上にするように横に倒します。

ここでpcケースの中身をよく見てみると対応しているマザーボードの大きさと数字が割り振られていると思います。(自分のpcケースの場合はMicroATXが1,Mini-ITXが2と書かれていました。)

周りを見てみると穴の横に数字が書いてあると思います。自身のマザーボードに対応する大きさの穴にスペーサーというものを取り付けていきます。スペーサーはpcケースに付属していると思います。

ネジとスペーサー(左:ネジ、右:スペーサー)

左が通常のネジ、右がスペーサーになります。このスペーサーを取り付けていきます。

取り付け後、マザーボードをpcケースに取り付けます。

pcケースにバックパネルと呼ばれる

バックパネル(引用)

このような出力装置のケースのような者が入っていると思います。これをマザーボードの部分といい感じになるようにセットしながらpcケースに取り付けてあげる必要があります。

自分のマザーボードの場合は

マザーボードネジ止め部分

この6つになりますね。これらをネジで固定していきましょう!

これでpcケースにマザーボードを設置できました。

pcケースについているケーブルの取り付け

次にpcケースにくっついているケーブルがいくつかあると思います。そちらをマザーボードの対応する部分に接続していきます。

自分が使ったのは

・pcケースファンのケーブル

・HD Audio

・USB3.0

・電源スイッチ類のコネクタ

です。

pcケースファンのケーブル

pcケースについてるファンからケーブルが出ていると思います。これをマザーボードの

pcケースファンを差し込む位置

ここにくっつけます。

HDAudio

pcケースについているケーブル達の一つにHDAudioと書いてあるケーブルがあります。

これをマザーボードの

HDAudioの接続場所

ここに取り付けます。HDAudioケーブルは穴が一つないはずなのでそこを合わせながら取り付けていきます。

電源スイッチ類のコネクタ

こちらは少しややこしいです。がそんなに難しいわけでもありません。

pcケースについているケーブルの中に何やら小さいケーブル達があるはずです。

自分のケースにはPowerSW,RESETSW,HDDLEDというケーブルが入っていました。これらをマザーボードの

電源スイッチ類コネクタの場所

ここに取り付けていきます。(似たような部分もありますが、右上がないところです。)

ここで位置と向きに注意が必要です。

位置は下の図のような感じで挿入します。

Power SW,RESET SW, HDD LED, Power LED

そして向きなんですがコネクタをよく見ると矢印が書いてあると思います。その矢印が書いてある方が+(プラス)になります。

USB3.0

これもまたpcケースのケーブル類の中にあります。青いケーブルです。

USB3.0(引用)

これをマザーボードの

USB3.0の場所

ここに取り付けます。

以上でpcケースのケーブル類は終わりです。次はGPU(グラフィックボード)の取り付けです!

GPU(グラフィックボード)の取り付け

なぜこの段階でGPUを取り付けるかというとこれより前に取り付けるとGPUが邪魔で他のコネクタが取り付けにくくなってしまうと感じたからです。

GPUを取り付ける前にまずpcケース自体のネジを外しておきます。

pcケース裏側(引用)

まず黄色い部分のネジを取り、その次に赤い部分のネジを取ります。

今回の自分のマザーボードはGPUを1つ取り付けるものだったので真ん中の2つのネジを外しました。(おそらく2つなら全て取り外すと思います。)

ネジ達は使いますが外した部品は使いません。でも捨てず一応どこかに保管しておきましょう。

さて、GPUをマザーボードに取り付けていきましょう。場所は

GPU場所

ここです。GPUもメモリの時と同様にレバーがあります。これを外してから入れます。

GPUは思ったより簡単に入ります。(メモリよりは力を入れやすいっていうのもあるかも)

GPUを取り付けたら先ほどネジを外した場所の当たりにちょうどいい感じでGPUの穴も来ると思うのでネジでくっつけてあげます。くっつけたら一番最初に取ったネジもくっつけてGPU取り付け完了です!

電源の取り付け

自分が買ったpcケース(ANTEC(DP301M))の説明書から抜粋したイラストを載せておきます。

電源位置

ここにpcケースのネジを使って固定していきます。

この説明書は左上のネジ位置が間違っているようですがそんな小さなことは気にしません。隣の穴から止めてあげます。

電源から出ているケーブルは次の「ケーブル類の取り付け」においてマザーボードに取り付ける位置を説明していくのでその位置に近そうなpcケースの穴から表へ通します。

電源についているケーブル類の取り付け

ここもなかなかの鬼門です。初めて見ると何が何だかよくわからないですよね。一つ一つ丁寧に説明していきます。

取り付け順番はどれからでも大丈夫ですが、大きいケーブルから取り付けていくとわかりやすいです。

今回も大きいケーブルから紹介していきます。

ATX(24/20ピン)

これは一番でかいケーブルです。

ATX24/20ピン(引用)

こんな感じのケーブルです。20+4に分けてある理由は20ピンにも24ピンにも対応できるためです。これを

ATX24ピン位置

ここに差し込んであげます。20ピンの右に4ピンを差し込む形になると思います。別々に差し込んでも20ピンと4ピンを繋げてから一緒に差し込んでも大丈夫ですが自分的には繋げてから差し込んだ方が楽かなと思いました。(別々に刺すと4ピンをはめるのに苦労しました)

ちなみにこのATX24/20ピン、一度はめると取り外すのがめちゃくちゃ固いです。。

取り外せないことはないですが、取り外すには指がとても痛くなるので、もし何らかの原因で失敗したら素手ではなく軍手などで外した方がいいかもしれません。

ATX4ピン

ATX4ピンはCPU補助電源とも呼ばれます。

ATX4ピン(引用)

このようなケーブルです。

これをマザーボードに指す場所はというと、、

ATX4ピン

ここです。ちなみにこの4ピンも失敗すると外す時、それなりに固いです。(ATX24ピンほどではないですが)

まあどちらにせよマザーボードやpcケースを変えようと思ったら外さなければいけないんですけどね

PCIe電源コネクタの取り付け

次にGPUの上に何やら指す場所がありますよね。そこにPCIe補助電源ケーブルというものを取り付けます。

今回自分が買ったRTX3070は8ピン×2を必要とします。

(6+2ピン)×2でもいいのかもしれませんが、GPUの箱に6ピン×2→8ピンに変換するアダプタが2つ入っていたのでこういうのが入っていたときはできるだけ6ピン×4→8ピン×2として使った方がいいです。(余裕を持たせた方がいいということです)

画像で見せた方が早いので

PCIe補助電源ケーブル(引用)

こんな感じのケーブルをGPUの上の部分に取り付けます。

電源をつける!

以上でpcが完成しました!

電源をコンセントにつなぎHDMI等の出力端子を用いてディスプレイにつないでスイッチを入れてみましょう!(GPUを取り付けているときはGPUのHDMI端子を使うこと!)

ディスプレイが写らないときは上で説明した何らかの工程でうまくいっていない可能性が高いです。

よくあるミスは

・メモリがきちんとはまっていない

・HDMIケーブルをマザーボードに挿してしまっている

等が考えられます。

基本的にATX24/20ピン、CPU補助電源、GPU補助電源に使うピン(マザーボード側)は全て埋まっているはずです。

これらのどこかに空きができてしまう場合は電源の推奨電力が足りていない可能性があります。

終わりに

以上自作pcに関して電源をつけるまでの流れを説明してきました。長くなりましたがその分丁寧に説明したつもりです。初心者の方の目にとまり参考にしていただければ嬉しいです。

どうしてもディスプレイが写らない等の問題があったらYoutubeを見るのもおすすめです。同じような問題を抱えた様々なYoutuberが動画をアップしているので参考になるかもしれません。

AmpereのGPUでPyTorchを動かすときに詰まった話

こちらはrioyokotalab Advent Calendar 2020の10日目の記事です

本題に入る前にちょっと雑談

上にあるリンクは研究室で行われているアドベントカレンダーです。研究室でブログを書いていこう!という企画だそうです。

こちらに参加しようと思った時に、自分はブログを書いたことがなく、どのように書いていくかもわからない。。そんな感じでした。

そんな時、サーバーを持っているじゃないか。。サーバーをレンタルすることもない!そんなこともありWebサーバーを立て、ブログサイトを立ち上げてみることにしました!そうしてできたのがこのサイトです。

AmpereGPUとは

NvidiaのGPUは大きく分けてKeplar,Maxwel Pascal,Volta,Turing,Ampereに分かれています。

XX50XX60XX70XX80XX90
Keplar750760770780
Maxwel950960970980
Pascal1050106010701080
Turing206020702080
Ampere307030803090
Nvidia GPU

下に行けば行くほど新しく、右に行けば行くほど性能はいいという感じです。

TuringのGPUには2050Ti、2080Tiといった”Ti”が付くものや、20XXSUPER といった”SUPER”が付くものがあり、これらはどちらも付いていないGPUよりも少し性能が良くなっています。

今回は一番下の現在新しいGPU(Ampere)において詰まった話をご紹介します。

これ、遅くない?と思ったきっかけ

自分のサーバーにはRTX3070を積んでいるのですが、自分にはpascalの1080Tiという1080よりも少し性能が良くなったGPUと、V100という一つ100万くらいするめちゃくちゃ高いGPUを使える環境がありました。

1GPUでの実験は基本的に自分のサーバーでやっていたのですが、、、

ある時、1080Ti、V100でも動かしてみようと思い、動かした結果。。

(ちなみに動かしているサンプルコードはCIFAR10をResnet18で1epochだけ学習するものです。)

GPU時間
V100約5秒
1080Ti約8秒
3070約26秒
あるプログラムの実行にかかった時間

ん???????

V100は3070よりも古いですがお値段が相当高い、とても高価なGPUなのでまあ早いのはわかります。

しかし、1080Tiと比べて3070が3倍以上時間がかかっているのは明らかにおかしい!!!

色々調べてみる

gemmを実行してみる

そもそもGPUの性能を発揮できているのか?と思い、https://github.com/enp1s0/gpu_perf のコードを借りてGPUのパフォーマンスを出力してみた結果。

GPUパフォーマンス
1080Ti1.072296e+01 [TFlop/s]
30701.312955e+01 [TFlop/s]
GPUのパフォーマンス

しっかり3070の方が性能が出ています。

ちなみにResnet18をはじめ、畳み込み層を計算するためにはcuDNNのインストールが必要になりますが、こちらはpytorchのインストールの際に自動で入るそうです。

プロファイラをとってみる

ubuntu serverではnsysコマンドを用いてプロファイラをとることができます。

こちらを1080Tiと3070で取ってみました

3070ではcuBLAS GEMMが全体の実行時間の50%を占めている状況

1080Tiではwinogradが全体の17%を占めている状況

という感じでした。ちなみに3080を持っている方にプログラムをお渡しして実行していただいても1080Tiよりは遅いという結果でした。

結局何が原因だったの?

結論から言うとPyTorchのサンプルコードに

torch.backends.cudnn.benchmark = True

この1行を埋め込むだけで3070だけ異常に速くなりました。

GPU時間
V100約5秒
1080Ti約8秒
3070約5.5秒
あるプログラムの実行にかかった時間

しっかり、PascalGPUよりは性能が出ていますね。V100と1080Tiは大きな変化は見られなかったです。

なぜこんなことが起きたかというとはっきりした原因はわかりませんが、

torch.backends.cudnn.benchmark = True

というのは畳み込みアルゴリズムを総当たりで探索するかどうかを設定するものです。

おそらく、AmpereGPUは新しいため、まだPyTorchに100%対応しておらず、デフォルトのアルゴリズムが遅いのでは?という結論に至りました。

新しすぎてもPyTorch側が対応していないとこんなにも遅くなってしまうのですね。。。。

wordpressにログインしようとしたらリダイレクトループ!!

wordpressにログインしようとしたらまた、ログイン画面に戻される。。。。

この繰り返しをリダイレクトループといいます。自分の場合はさらにログイン画面のデザインもおかしかったです。

こういうバグってどこでエラーが起きてるかってわかりにくいですよね。

普通は

/var/log

を見に行くと思うのですがwordpressならnginxやphp等の下で動いているのでそれらがエラーを出していないか等すべてログファイルを見に行かなければなりません。

今回の場合はどこのログにもエラーは載っていませんでした。

自分が解決できた方法

原因はwordpressフォルダ直下にあるwp-config.phpの記述の間違いでした。

wordpressをインストールした際にwp-config.phpに色々コードを加えたと思うのですがそちらを加える位置に問題がありました。wp-config.phpをよく見てみると、、、、

/* That's all, stop editing! Happy publishing. */

と書いてある行があると思います。この行より下は基本的にいじったりコードを追加したりしてはいけません!

ここより下にあるコードをすべて上にもってきたらデザインも直り、ログインのリダイレクトループも解消されました!

要するにちゃんと英語を読みましょうという話です。

さらに同じ変数の定義を2回以上しているとこれもまたリダイレクトループの原因となります。(様々なサイトからコピペしている方要注意!)