ローリングコンバットピッチなう!

AIとか仮想化とかペーパークラフトとか

飛行機とか新幹線の謎の空き席

[diary]飛行機とか新幹線にはトラブル対応用にリザーブされた席が(多分)あるというお話

先週、こんな記事がバズっていて、ああ、そう言えばと思いつつ書けてなかったので、ちょっとディープラーニングとかの話題をお休みして書きます。
snjpn.net
この記事の車掌の行動の是非自体は特に批評しません。事実ならGJだなと思いますが、ちょっとフェイク臭も感じるので。

この年末年始、1/4に帰省先から新幹線でUターンしました。
1/4はUターンラッシュのど真ん中、昨年まではこの日程で新幹線を乗るのは避けていたのですが、子供の学校のスケジュールやらなんやらで今年はUターンラッシュど真ん中に乗る事になり、案の定というか普通席の指定券が取れませんでした。12/4の朝10時に予約したかったのですが色々あって結局昼ごろ予約したらもうグリーン車しか空いておらず、多分人生で3度目くらいの新幹線グリーン車に乗りました。嫁は想定外にグリーン車に乗れてちょっと喜んでましたが。

で、件の記事見て思い出したのですが、1/4に乗った新幹線は某駅始発でその始発駅からグリーン車に乗りました。流石にグリーン車もほぼほぼ満席に見えたのですが、始発駅の時点では自分が乗った車両の最前列は空いていました。
なのですが、次の駅につく前の時点でいつの間にやら左右に一名づつ乗客が。そしてそのどちらも車掌さんと何やらやり取りしていて、車掌さんの態度、雰囲気からなんとなく「厄介」臭がしたんですよ。
これは全く根拠は無くて自分の感覚だけなので、間違っているかもしれませんが、おそらく最前列に乗った両名共にもともとその席の指定券は持っておらず、その場で精算なりしていた様に見えました。

で、件の記事で車掌さんが「グリーン車に空きがありましたので、」って言っているわけですが、これは空きがあったのではなく、多分空けてあったのだろうと。
もちろんJRの人に聴いたわけでは無いのでこれは推測なんですが、例えば飛行機なんかは特に長距離国際線だと明らかに一定数の座席を普通の人は予約出来ない様にキープしてあり、どんなに満席でも意図的に空き席を作ってあるように見えます。これは状況により乗員が使うためだったり、機内にトラブル発生時に乗客を一旦移動させたりするためのリザーブなんだろうと思います。

色んなケースがあるんですが、いわゆるクレーマー対策的な場合、酔っ払って暴れる乗客が出た場合の隔離用、もしくは急病人が出た場合に急病人の救護スペースを作るために他の乗客を移動させるなど、万が一に備えたリザーブスペースが機内には必要になります。(短距離便だと、出発地に引き返す場合もありますが、長距離便で例えば太平洋の真ん中だと最低でも数時間は機内で対処するしか無いので)

以前、家族で国際線に乗った際、当時息子はまだ幼稚園児だったのですが、機体のほぼ最後尾付近に座っていたところ、通路またぎで我々家族の隣にいた男性客が多分酒飲みすぎたか暴れ始めた事がありました。米系のエアラインで男性の客室乗務員2名がその男性客の監視に付き、他の乗客に害が無い様にガードしていたのですが、うるさかったのと、まだうちの息子が小さかったので万が一を避けるために、前に席を用意したので移って下さいと言われました。一瞬ビジネスかなと期待しましたが、それはかなわず、しかしエコノミーの最前列の足元の広い席に移してくれました。

出張で国際線に乗った時に体調を崩した乗客が居て、その隣席に座っていた人はやはりどこかの席に案内されて移動していました。

今日は満席です等のアナウンスされていても、何かあるとどこからか空き席が出てくるのは基本的にはリザーブされているからだと思います。

で、多分新幹線も可能な限りはそういった用途の席を空けているんじゃないかな?と想像するのですが、多目的室等もあるのでグリーンを敢えて空けているかは、どうなのかな?という感じで確信はありません。自分が見たのはたまたまだったのかもしれません。

ただ、偶にこういう「厄介対応」を期待して確信犯的に乗員にクレーム付ける輩もいたりするので、そういう場合は厳しい対応とって欲しいと思うのですが、車掌さんがラグビー日本代表レベルのガタイじゃないと厳しいのかもしれません。そういう意味で件の記事の車掌さんの対応はフェイクっぽいな?ホント?という感想を抱くのですが。

エアラインでも海外のエアラインだと結構ガタイの良いお兄さんが客室乗務員だったりするのですが。以前にエールフランスに乗った時は海兵隊あがりみたいなスキンヘッドのお兄さんが客室乗務員していたことがあります。日本の鉄道や航空会社も、乗務員に保安要員としての資質を重視した採用、配置をもっとしても良いのではないかなとも思っています。

【PyTorch始めました】PyTorchで書いたMNIST用のスクリプトをGPU化

[technology]PyTorchでGPUを使う


以下のエントリーの続きです。Chainer使いがPyTorchに移行するための備忘録です。
rc30-popo.hatenablog.com
rc30-popo.hatenablog.com
rc30-popo.hatenablog.com

PyTorchでGPUを使う場合(NVIDIAのドライバーやCUDAはインストール済みの前提で)、トレーニング前にモデルとデータ(トレーニングデータ、教師データ)をto('cuda')でGPUに転送するのみです。
推論結果を確認する場合は、モデルからforward()された結果に対してto('cpu')もしくはcpu()でCPUにデータを戻します。

下記のコードでは一応torch.cuda.is_avaiable()でGPU使用可否をチェックし、GPU(CUDA IF)が無ければCPUを使う様にしてあります。

また前回までのサンプルでは、学習結果のテスト時にテスト用データを1件づつ推論させていて効率が悪いので、纏めて推論させて、その後に結果を照合する様に変更しました。

GPU化したコード:

# -*- Coding: utf-8 -*-

# Numpy
import numpy as np
# Chainer
# ★Chainerのdatasetsからmnistを引っ張るためchainerは残す
import chainer
# ★Pytorchをインポート
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

print('MNIST Deep Learning sample by PyTorch')
print(' PyTorch Version: ',torch.__version__)

# GPU availability check
# GPUは使用可能ならdeviceを'cuda'に設定、GPU無し環境では'cpu'を使用
if torch.cuda.is_available():
    device = 'cuda'
else:
    device = 'cpu'
print(' Device: ',device)

train, test = chainer.datasets.get_mnist()

x_train = []
x_test  = []
t_train = []
t_test  = []

for line in train:
    x_train.append(line[0])
    t_train.append(int(line[-1]))

for line in test:
    x_test.append(line[0])
    t_test.append(int(line[-1]))

x_train = np.array(x_train,dtype=np.float32)
x_test = np.array(x_test,dtype=np.float32)
# ★PyTorchでは分類クラスはintではなくlong
t_train = np.array(t_train,dtype=np.int64)
t_test = np.array(t_test,dtype=np.int64)

x_train = x_train.reshape(len(x_train),1,28,28)
x_test = x_test.reshape(len(t_test),1,28,28)

        
# DNN class ★モデルは前回と同じ
class DNN(nn.Module):
    def __init__(self):
        super(DNN,self).__init__()
        self.cv1 = nn.Conv2d(1,5,4)
        self.cv2 = nn.Conv2d(5,10,4)
        self.l1 = nn.Linear(10 * 4 * 4,100)
        self.l2 = nn.Linear(100,10)
    def forward(self,x):
        c = F.max_pool2d(F.relu(self.cv1(x)),2)
        c = F.max_pool2d(F.relu(self.cv2(c)),2)
        # Chainerと異なり、全結合層に入力する前にshape変換が必要
        c = c.view(-1,10 * 4 * 4)
        h = F.relu(self.l1(c))
        h = self.l2(h)
        return h

# Create DNN class instance
# ★ to(device)を追加してGPUに転送
model = DNN().to(device)

# Set optimizer
# ★optimizerをセット
optimizer = optim.Adam(model.parameters())

# Number of epochs
n_epoch = 20

# batch size
batch_size = 1000

# Execute Training
for epoch in range(n_epoch):
    sum_loss = 0
    perm = np.random.permutation(60000)
    for i in range(0, 60000, batch_size):
# ★x_trainとy_trainをpytorchのTensorに変換
#   ここで変換は効率悪い気もするけど..元のコードベースを崩さないため
# ★ to(device)を追加してGPUに転送
        x = torch.from_numpy(x_train[perm[i:i+batch_size]]).to(device)
        t = torch.from_numpy(t_train[perm[i:i+batch_size]]).to(device)
        y = model.forward(x)
# ★cleargrads()はzero_grad()に
        model.zero_grad()
# ★softmax_cross_entropy()→cross_entropy()
        loss = F.cross_entropy(y,t)
        loss.backward()
#  ★optimizer.update()はoptimizer.step()に
        optimizer.step()
        sum_loss += loss.data*batch_size

    print("epoch: {}, mean loss: {}".format(epoch, sum_loss/60000))

# Execute Test
cnt = 0
# ★テストデータを纏めて推論するように改善
x = torch.from_numpy(x_test).to(device)
y = model.forward(x)
# ★照合用に推論結果yをCPUに戻し、numpyの行列に変換
y = y.cpu().detach().numpy()
# ★1点づつ答え合わせ
for i in range(10000):
    t = t_test[i]
    yi = np.argmax(y[i])
    if t == yi:
        cnt += 1

# Display Result
print("accuracy: {}".format(cnt/(10000)))

GPU版MNIST実行結果(20epoch):

$ time python mnist_cnn_test_torch_gpu.py
MNIST Deep Learning sample by PyTorch
 PyTorch Version:  1.3.1
 Device:  cuda
epoch: 0, mean loss: 1.8325331211090088
epoch: 1, mean loss: 0.4075491726398468
epoch: 2, mean loss: 0.23716536164283752
epoch: 3, mean loss: 0.18152500689029694
epoch: 4, mean loss: 0.14973215758800507
epoch: 5, mean loss: 0.12893804907798767
epoch: 6, mean loss: 0.11485324054956436
epoch: 7, mean loss: 0.10463400930166245
epoch: 8, mean loss: 0.09558816999197006
epoch: 9, mean loss: 0.08927364647388458
epoch: 10, mean loss: 0.08328855782747269
epoch: 11, mean loss: 0.07930488139390945
epoch: 12, mean loss: 0.07505807280540466
epoch: 13, mean loss: 0.07105353474617004
epoch: 14, mean loss: 0.06764773279428482
epoch: 15, mean loss: 0.06459520757198334
epoch: 16, mean loss: 0.06436379253864288
epoch: 17, mean loss: 0.059575922787189484
epoch: 18, mean loss: 0.058406319469213486
epoch: 19, mean loss: 0.05537751689553261
accuracy: 0.9814

real	0m23.489s
user	0m18.544s
sys	0m5.716s

CPU版MNIST実行結果(20epoch):

$ time python mnist_cnn_test_torch.py 
epoch: 0, mean loss: 1.6286011934280396
epoch: 1, mean loss: 0.4382973611354828
epoch: 2, mean loss: 0.2794622778892517
〜中略〜
epoch: 17, mean loss: 0.06488480418920517
epoch: 18, mean loss: 0.06439197808504105
epoch: 19, mean loss: 0.06153048202395439
accuracy: 0.9814

real	1m38.296s
user	7m17.184s
sys	3m44.128s

GPUで処理時間1/4くらいに短縮されています。