旅行好きなソフトエンジニアの備忘録

プログラミングや技術関連のメモを始めました

【アイトラッキング】 RGBカメラで視線計測できるサービス

iMotionsのブログで角膜反射法での視線計測と、ウェブカメラベースの視線計測が比較されていました。

imotions.com

ウェブカメラベースの視線計測は角膜反射法と比較して精度が劣りますが、逆に精度が重要でなければ検討しても良いかもしれません。上記リンクは海外のサービスのみが紹介されていますが、日本であればオムロンNECがカメラから視線計測する技術を持っていそうです。

【Python】 実行スクリプトからの相対パスでファイルにアクセスする

以下のサイトに方法が書いてありました。

qiita.com

【Python】 PyTorchで自前のロス関数を定義する

Kerasと違ってPyTorchで自前のロス関数を定義するのは大変かなと思ったのですが、Kerasとほぼ同じやり方で出来ました。

#1. ロス関数を定義して
def dice_coef_loss(input, target):
    small_value = 1e-4

    input_flattened = input.view(-1)
    target_flattened = target.view(-1)
    intersection = torch.sum(input_flattened * target_flattened)
    dice_coef = (2.0*intersection + small_value)/(torch.sum(input_flattened) + torch.sum(target_flattened) + small_value)
    return 1.0 - dice_coef

#2. backwardするだけ(outputs, labelsは共にVariable)
outputs = model(X)
loss = dice_coef_loss(outputs, labels)
loss.backward()

【Python】 Perceptual Hashを使って画像の類似度を調べる

一年くらい前にヒストグラムを使って画像の類似度を調べる方法をメモしていたのですが、今回はそれとは別の方法を見つけたのでその記事をメモしておきます。 ni4muraano.hatenablog.com

tech.unifa-e.com

上記の記事で取り上げられているimagehashというライブラリは以下に使い方が書いてあり、インストールは普通に"pip install imagehash"で出来ました。 github.com

【Python】 PyTorchでMNISTを試す

Kerasともう一つ何かディープラーニングフレームワークを試したいと思いPyTorchに手を出そうかと思っています。で、早速Hello WorldとしてMNISTを写経しました。

環境

Windows10
Anaconda4.2.0
PyTorch0.3.0
Torchvision0.2.0

Windowsへのインストール

1 condaのアップデート

conda update conda

2 PyTorchのインストール(OS, CUDAバージョンでコマンドが異なるので注意

conda install -c peterjc123 pytorch cuda80

3 Torchvisionのインストール

pip install torchvision

写経元

www.udemy.com

参考になるサイト

hacks.deeplearning.jp

ソース

ざっと見た感じKerasよりはやっぱり複雑なものの、理解できないようなものでも無さそうです。最初ラベルをOne-Hot Encodingしなくて良いのかと思いましたが、ここを見るとラベルのまま渡して大丈夫そうです。
(注) DataLoaderを使うとエラーが出て解決できなかったためDataLoaderを使っていない。このため標準的な書き方にはなってなさそう。

import numpy as np
import torch
import torch.nn as nn
import torchvision.transforms as transforms
import torchvision.datasets as dsets
from torch.autograd import Variable
from torch.optim import SGD

#1. Load Dataset
train_dataset = dsets.MNIST(root='data', train=True, transform=transforms.ToTensor, download=True)
test_dataset = dsets.MNIST(root='data', train=False, transform=transforms.ToTensor)

#2. Make Dataset Iterable(DataLoaderを使うとエラーとなったため使っていない)
batch_size = 100
num_epochs = 10
#train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
#test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=False)

#3. Create Model Class
class CNNModel(nn.Module):
    def __init__(self):
        super(CNNModel, self).__init__()

        self.cnn1 = nn.Conv2d(in_channels=1, out_channels=16, kernel_size=5, stride=1, padding=2)
        self.relu1 = nn.ReLU()
        self.maxpool1 = nn.MaxPool2d(kernel_size=2)

        self.cnn2 = nn.Conv2d(in_channels=16, out_channels=32, kernel_size=5, stride=1, padding=2)
        self.relu2 = nn.ReLU()
        self.maxpool2 = nn.MaxPool2d(kernel_size=2)

        self.fc1 = nn.Linear(in_features=32 * 7 * 7, out_features=10)

    def forward(self, x):
        out = self.cnn1(x)
        out = self.relu1(out)
        out = self.maxpool1(out)

        out = self.cnn2(out)
        out = self.relu2(out)
        out = self.maxpool2(out)

        # KerasのFlattenに相当する処理を実行している
        # (100, 32, 7, 7) -> (100, 32*7*7)
        out = out.view(out.size(0), -1)

        out = self.fc1(out)

        return out

#4. Instantiate Model Class
model = CNNModel()
# モデルをGPUに転送する
model.cuda()

#5. Instantiate Loss Class
criterion = nn.CrossEntropyLoss()

#6. Instantiate Optimizer Class
learning_rate = 0.01
# model.parameters returns kernel info
optimizer = SGD(model.parameters(), lr=learning_rate)

#7. Train Model
def normalize(X):
    return X/255.0

iter = 0
X_train = train_dataset.train_data
X_train = normalize(X_train.numpy()).astype(np.float32)
Y_train = train_dataset.train_labels
# CrossEntropyLossはラベルがLong型を期待している
# CrossEntropyLossはOne-Hotじゃなくて3とか7とかのラベルを期待している
Y_train = Y_train.numpy().astype(np.int64)
X_test = test_dataset.test_data
X_test = normalize(X_test.numpy()).astype(np.float32)
Y_test = test_dataset.test_labels
Y_test = Y_test.numpy().astype(np.int64)
for epoch in range(num_epochs):
    # データをシャッフルする
    p = np.random.permutation(X_train.shape[0])
    X_train = X_train[p]
    Y_train = Y_train[p]
    for i in range(X_train.shape[0]//batch_size):
        images = X_train[i*batch_size:(i+1)*batch_size, :]
        images = images[:, np.newaxis, :, :]
        labels = Y_train[i*batch_size:(i+1)*batch_size]
        # Numpy -> Tensor -> Variableに変換してGPUへ転送する
        images = Variable(torch.from_numpy(images)).cuda()
        labels = Variable(torch.from_numpy(labels)).cuda()

        optimizer.zero_grad()
        outputs = model(images)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

    # エポック毎にテストデータ正解率チェック
    correct = 0
    total = 0
    for i in range(X_test.shape[0]//batch_size):
        images = X_test[i*batch_size:(i+1)*batch_size,:]
        images = images[:, np.newaxis, :, :]
        labels = Y_test[i*batch_size:(i+1)*batch_size]
        images = Variable(torch.from_numpy(images)).cuda()
        outputs = model(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.shape[0]
        predicted = predicted.cpu().numpy()
        correct += (predicted == labels).sum()
    accuracy = 100*correct/total
    print('Epoch: {}. Loss: {}. Accuracy: {}'.format(epoch, loss.data[0], accuracy))

【Python】 VAE(Variational Auto Encoder)の写経

書籍「Deep Learning with Python」にMNISTを用いたVAEの実装があったので写経します(書籍では一つのファイルに全部書くスタイルだったので、VAEクラスを作ったりしました)。

VAEの解説は以下が詳しいです。
qiita.com

実装ですが、まずは以下をvae.pyに書きます。

import numpy as np
from keras import Input
from keras.layers import Conv2D, Flatten, Dense, Lambda, Reshape, Conv2DTranspose, Layer
from keras.models import Model
from keras.metrics import binary_crossentropy
import keras.backend as K

class CustomVariationalLayer(Layer):
    def set_z_mean(self, z_mean):
        self._z_mean = z_mean

    def set_z_log_var(self, z_log_var):
        self._z_log_var = z_log_var

    def _vae_loss(self, x, z_decoded):
        x = K.flatten(x)
        z_decoded = K.flatten(z_decoded)
        reconstruction_loss = binary_crossentropy(x, z_decoded)
        regularization_parameter = -5e-4 * self._compute_KL_divergence(self._z_mean, self._z_log_var)
        return K.mean(reconstruction_loss + regularization_parameter)

    def _compute_KL_divergence(self, z_mean, z_log_var):
        return K.mean(1 + z_log_var - K.square(z_mean) - K.exp(z_log_var), axis=-1)

    def call(self, inputs):
        x = inputs[0]
        z_decoded = inputs[1]
        loss = self._vae_loss(x, z_decoded)
        self.add_loss(loss, inputs=inputs)
        return x

class VAE(object):
    def __init__(self, image_shape, latent_dim):
        self._latent_dim = latent_dim

        # Encoding
        input_img = Input(shape=image_shape)
        x = Conv2D(32, 3, padding='same', activation='relu')(input_img)
        x = Conv2D(64, 3, padding='same', activation='relu', strides=(2, 2))(x)
        x = Conv2D(64, 3, padding='same', activation='relu')(x)
        x = Conv2D(64, 3, padding='same', activation='relu')(x)
        shape_before_flattening = K.int_shape(x)
        x = Flatten()(x)
        x = Dense(32, activation='relu')(x)
        z_mean = Dense(latent_dim)(x)
        z_log_var = Dense(latent_dim)(x)

        # Sampling
        z = Lambda(self._sampling)([z_mean, z_log_var])

        # Decoding
        decoder_input = Input(K.int_shape(z)[1:])
        x = Dense(np.prod(shape_before_flattening[1:]), activation='relu')(decoder_input)
        x = Reshape(shape_before_flattening[1:])(x)
        x = Conv2DTranspose(32, 3, padding='same', activation='relu', strides=(2, 2))(x)
        x = Conv2D(1, 3, padding='same', activation='sigmoid')(x)
        self._decoder = Model(inputs=decoder_input, outputs=x)
        z_decoded = self._decoder(z)
        l = CustomVariationalLayer()
        l.set_z_mean(z_mean)
        l.set_z_log_var(z_log_var)
        y = l([input_img, z_decoded])

        self._vae = Model(input_img, y)

    def _sampling(self, args):
        z_mean, z_log_var = args
        epsilon = K.random_normal(shape=(K.shape(z_mean)[0], self._latent_dim), mean=0.0, stddev=1.0)
        return z_mean + K.exp(z_log_var)*epsilon

    def get_model(self):
        return self._vae

    def get_decoder(self):
        return self._decoder


後は以下をmain.pyに書けばVAEに文字を生成させることができます。

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
from keras.optimizers import RMSprop
from keras.datasets import mnist
from vae import VAE

img_shape = (28, 28, 1)
batch_size = 32
latent_dim = 2

(x_train, _), (x_test, y_test) = mnist.load_data()
x_train = x_train.astype('float32')/255.0
x_train = x_train.reshape(x_train.shape + (1,))
x_test = x_test.astype('float32')/255.0
x_test = x_test.reshape(x_test.shape + (1,))

vae = VAE(img_shape, latent_dim)
decoder = vae.get_decoder()
vae = vae.get_model()
vae.compile(optimizer=RMSprop(), loss=None)
history = vae.fit(x=x_train, y=None, shuffle=True, epochs=10, batch_size=batch_size)
with open('loss.txt', 'a') as f:
    for loss in history.history['loss']:
        f.write(str(loss) + '\r')

n = 15
digit_size = 28
figure = np.zeros((digit_size*n, digit_size*n))
grid_x = norm.ppf(np.linspace(0.05, 0.95, n))
grid_y = norm.ppf(np.linspace(0.05, 0.95, n))

for i, yi in enumerate(grid_y):
    for j, xi in enumerate(grid_x):
        z_sample = np.array([[xi, yi]])
        z_sample = np.tile(z_sample, batch_size).reshape(batch_size, 2)
        x_decoded = decoder.predict(z_sample, batch_size)
        digit = x_decoded[0].reshape(digit_size, digit_size)
        figure[i*digit_size:(i+1)*digit_size,
               j*digit_size:(j+1)*digit_size] = digit
plt.figure(figsize=(10, 10))
plt.imshow(figure, cmap='Greys_r')
plt.show()

plt.show()を実行したところで以下のような図が描画されます。
f:id:ni4muraano:20180101223102p:plain

【WPF】 バインドした数値の表示する桁数を指定したい

TextBoxに表示する数値データを小数点一桁目までしか表示させたくなかったのですが、以下のようにStringFormatを利用することで指定可能でした(ここを参考)。

<TextBox Text="{Binding Value, StringFormat={}{0:N1}}"/>