まままのテックブログ

機械学習、統計、信号処理のまとめと仕事の役に立つツール紹介をします。

Pytorchでパーセプトロンを実装してみた

人間のニューロン活動を模したモデルであるパーセプトロンの実装をしてみました。

ニューラルネットについて

機械学習は推定値と観測値の誤差を更新していくことで モデルを構築する。その時の誤差を目的関数といい、通常 MSE や交差エントロピー誤差関数が使われる。この誤差を最小にするようにパラメータを更新していく。このパラメーターの更新には全てのデータセットを入力する必要があるがそれは現実的ではないので確率的勾配降下法などを用いて計算負荷を抑える工夫をする。

パーセプトロン

受け取った電気の量がしきい値を超えると発火するモデル。

入力信号を\boldsymbol{x}、重みを\boldsymbol{w}、活性化関数をf、出力信号を\boldsymbol{y}とすると、

\boldsymbol{y} = f(\boldsymbol{w}^T \boldsymbol{x})

条件

二値分類する時はシグモイド関数で他クラス分類するときは softmax 関数を使う。

コード

import numpy as np
from sklearn import datasets
from sklearn.utils import shuffle
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt
from sklearn.utils import shuffle
from sklearn.model_selection import train_test_split

class SP(nn.Module):
  def __init__(self, input_dim, output_dim):
    super().__init__()
    self.classifier = nn.Sequential(
        nn.Linear(in_features=input_dim, out_features=output_dim),
        nn.Sigmoid()
    )
  
  def forward(self, x):
    out = self.classifier(x)
    return out

まずモデルのクラスをつくる。今回のシングルパーセプトロンのクラスの入力には入力の次元、出力の次元を与えている。 nn.seqentialで入力の計算器と活性化関数を順々に定義することができる。 forward関数はcall関数として扱われる。 入力をxとして順伝播をする。

"""
1. データの準備
"""
device = torch.device("cuda")
d = 2
N = 20
mean = 5.
x1 = torch.randn(N, d) + torch.tensor([0, 0])
x2 = torch.randn(N, d) + torch.tensor([mean, mean])
t1 = torch.zeros(N)
t2 = torch.ones(N)
x = torch.cat((x1, x2), axis=0)
t = torch.cat((t1, t2), axis=0)
x_train, x_test, t_train, t_test = train_test_split(x, t, test_size=0.2)

pytorchでは GUI を使う際にコードで認識する。device変数に入力する。 入力2、出力1のパーセプトロンを用いて 0周辺の値と5周辺の値を線形分離する。 データを まとめてそれを訓練データとテストデータに分ける。テストサイズを0.2にすることで80%が訓練データとなる。

"""
2. モデルの構築
"""
model = SP(2, 1).to(device)
"""

モデルインスタンスを生成。

"""
3. モデルの学習
"""
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)
def compute_loss(t, y):
  return criterion(y, t)

def train_step(x, t):
  model.train()
  y_pred = model(x)
  loss = compute_loss(t, y_pred)
  optimizer.zero_grad() #勾配の初期化
  loss.backward() #勾配をすべてのノードに伝播
  optimizer.step() #勾配からパラメータを更新する
  return loss

誤差関数目的関数のインスタンスを作る、そして最適化の手法のインスタンスを作る。 この時 SGD を使う時はモデルのパラメータを初期化する 処理が必要で、 LRはラーニングレートでハイパーパラメータである。 訓練時は訓練モードにする。その後誤差を計算。そして勾配を全て初期化した後に 勾配を全てのノードに伝播する。そして勾配からパラメーターを更新し、ロスを出力する

epochs = 20
batch_size = 10
n_batches = x_train.shape[0] // batch_size

for epoch in range(epochs):
  train_loss = 0.
  x_, t_ = shuffle(x_train, t_train)
  x_ = torch.tensor(x_).to(device)
  t_ = torch.tensor(t_).to(device)

  for n_batch in range(n_batches):
    start = n_batch * batch_size
    end = start + batch_size
    loss = train_step(x_[start:end], t_[start:end])
    train_loss += loss.item()
  
  print("epoch: {}, loss: {:,.3}".format(epoch+1, train_loss))

ミニバッチ法を使用する。エポック数を20、バッチサイズを10として 訓練データを10個のバッチに分ける。訓練データと正解データをシャッフルしそれらをデバイスに入力する。バッチごとに誤差関数を出力しそれを足し合わせていく。

"""
4. モデルの評価
"""
def test_step(x, t):
  x = torch.tensor(x).to(device)
  t = torch.tensor(t).to(device)
  model.eval()
  preds = model(x)
  loss = compute_loss(t, preds)
  return loss, preds

loss, preds = test_step(x_test, t_test)
test_loss = loss.item()
preds = preds.data.cpu().numpy() > 0.5
test_acc = accuracy_score(t_test, preds)
print("test_loss: {:.3f}, test_acc: {:.3f}".format(test_loss, test_acc))

モデルを評価バージョンモードにする。正解度を出力する。

結果

1次直線で分類できている。 パーセプトロンはデータ群を直線で分類できる。

f:id:mamama039356:20210111231933p:plain

所感

pytorchと tensorflow で誤差を計算する引数の順番が逆なので気をつける。値を小数にしてnumpyは使わない。

Markdown形式で編集できる用語集向けwiki Knowledgeの紹介

f:id:mamama039356:20210110181435p:plain

概要

GROWIなどの高性能wikiはノウハウやマニュアルをまとめるにはよいのですが、用語をまとめるだけであればシンプルなwikiでまとめたいところです。そこでGROWIと同じようにMarkdownで編集できてツリー構造をしていないwiki、Knowledgeを紹介します。

条件

環境

  • Windows10
  • Docker-compose
  • WSL2
  • Chrome

デプロイ

  1. docker-knowledgeリポジトリをクローン

GitHub - support-project/docker-knowledge: Docker file for knowledge

git clone https://github.com/support-project/docker-knowledge.git
  1. コンテナを起動
docker-compose up -d
  1. ブラウザーからlocalhost:8080に接続

結果

ホーム画面

ホーム画面です。非ツリー構造なので記事の一覧が表示されます。

f:id:mamama039356:20210110180737p:plain
ホーム画面

記事画面

f:id:mamama039356:20210110181331p:plain
記事画面

所感

タグ付機能があるので、調べたい分野の用語を一通り調べられる用語集が作れそうです。 社内向けの用語集として使ってみてはいかがでしょうか。

Markdown形式で編集できるwiki GROWIの紹介

概要

f:id:mamama039356:20210110131047p:plain

マークダウンで書けて機能が豊富なwikiです。様々なwikiを試しましたが、GROWIはすべて網羅しているwikiだと思います。社内、家族、個人用として知識やマニュアルをまとめる際に使用してみてはいかがでしょうか。詳細は以下を参照ください。 GROWI Docs

条件

環境

  • Windows10
  • Docker Compose
  • WSL2
  • Chrome

デプロイ

  1. githubからソースコードをダウンロード Read.meに書いてある通りに、ローカル環境に落とし込む。

https://github.com/weseek/growi-docker-compose/blob/master/README.md

  1. Docker-compose ディレクトリ内に入って、Docker-composeで全イメージファイルをダウンロードする。
cd growi
docker-compose up
  1. コンテナの動作確認 ダウンロード完了後、アプリが動いているかを確認する。
docker-compose ps
  1. サーバーに接続 localhost:3000 に接続する。

結果

ホーム画面

ホーム画面もマークダウンで編集可能です。 デフォルトではページ一覧とSlackのログ、サイドバーが配備されています。

f:id:mamama039356:20210110125753p:plain
GROWI ホーム画面

ツリー構造

各記事はツリー構造で管理されます。タグ付けもできるので情報整理もしやすいです。

f:id:mamama039356:20210110131425p:plain
ツリー構造

記事

このようにマニュアルも作成できます。

f:id:mamama039356:20210110130407p:plain
テスト

検索機能

Elasticsearchが入っています。

f:id:mamama039356:20210110131550p:plain
検索窓

アカウント認証機能

アカウントにアクセス権を設定できます。

いいね!機能

f:id:mamama039356:20210110131852p:plain
いいねロゴ

コメント機能

f:id:mamama039356:20210110131946p:plain
コメント

所感

直感的なUIでチーム運用に必要な機能が一通りそろっており、個人運用としても使えます。 プラグインも豊富でカスタマイズもできます。 マイナスの点はホーム画面のコンテンツの画面に一部表示されない記事があることです。表示する階層を設定すれば対処できるかもしれません。 プラグインはdocker-composeからではインストールできないので注意が必要です。

ラジオの文字起こし

言ったことを記事に書きたい

ままま日記以外にも記事を書くことがあるのですが、良い記事を書くには労力がかかり、楽に考えを文字で発信したいと考えました。

私には文才がないので、書きたいことを声に出して録音し、音声認識で文字に起こして、そのまま記事にすれば下手の文章より伝わりやすいかもと考えました。

手始めにラジオの文字起こしをしてみます。

 

使用したもの

 

方法

VB-Audio Virtual Cable で音声入力と音声出力をつなげて、音声ファイルをパソコンで流し、それを文字起こしソフトの入力に入れます。

 

結果

私の好きなラジオ「有吉弘行のSUNDAY NIGHT DREAMER」の一部を使い文字起こしをしてみました。

 

f:id:mamama039356:20180909025016p:plain

 

高い精度で文字を起こしており、さすがGoogleですね。

はがき職人の秀逸でお下劣な文章がそのまま文字に起こされてます。

それにしても、よくこんな文章を書けるなー(笑)

 

まとめ

精度が高いので書きたいことを言って記事作成の補助に使えそうです。

香水レコメンドシステムの開発①

IoT, ビッグデータを用いた香水レコメンドシステムの開発

今進めているモノづくりの中の一つで、IoT, ビッグデータを用いて香水をレコメンドするシステムを開発するというプロジェクトを大学から支援から受けて進めています。

本プロジェクトに関して初めての投稿なので、概要、進捗、問題を書こうと思います。

というのもここにきて、シチュエーションに最適な香りというのがそもそも存在しないのではないかと疑い、壁になっているので状況を整理しておこうかと思いました。

概要

f:id:mamama039356:20180908153640p:plain

今までは消費者が香水を自らECや店舗で選んでいましたが、商品の情報量の多さから情報オーバーロードが生じる、また一瓶買いをすることからいろんな香りを楽しめないという改善点があります。

香水の使用に関する課題として、ユーザーは正しい使い方ができていない場合があり、知らず知らずに香害を引き起こしているケースがあります。

こういった課題は、香水の選択をシステム化することで解決すると考えられ、そのシステム開発に取り組んでいます。

シチュエーションに対して最適な香水をレコメンドしシチュエーションをビッグデータとして扱い、機械学習によって商品群の中から商品をレコメンドし、ユーザーが使用したもののデータを収集することでレコメンドのサイクルを作ります。

サービス化することができれば、情報量0でいろんな香りをコスパ良く、おしゃれに(正しく)香水を使うことができます。

 

進捗

計画を立て、何を使えば実現できるかということを把握して香水ステーションと呼ばれるインターフェースのプロトタイプを作製しています。

プロトタイプはできそうだが、ソフトの方で壁があり、どうしようかといったところ。

問題

香りとシチュエーションにほとんど相関がないこと、⑵人の個体間で香りの趣向がまったく異なるといったことから、シチュエーションに最適な香水をレコメンドできないというのが課題です。

⑵は個人の香りの趣向をくみ取らないサービス、つまり失敗しない香水レコメンドシステムや香水初心者に向けたレコメンドシステムといったサービスであれば、問題を回避することができるが、⑴の問題が深刻。

なぜなら、香水をシステム的にレコメンドすることができないことになるからです。

レコメンドする際にある程度相関があれば教師なし学習で解決できるが、相関が小さすぎるとシチュエーションで分類ができません

例えば夏の暑い日のデートでは、甘い匂いよりもキリっとした柑橘系の香りがいいということは分かりますが、柑橘系のどれがいいのかは分かりません。

絞られたシチュエーションならいいですが、気温、湿度、天気ではそもそも何々系というのも決められません。

フローラル、シトラス、樹脂系、etc、またこれが混合したものなど、そもそも分類できないものもあり、レコメンドに限界が生じます。

香りは分子で構成されるので、香りの強度や種類を数値的に扱って比較することが難しく、香りの印象も人間の言葉によってしか評価できないことから、香りとシチュエーションを一対一対応するのは難しいです。

当初は、ある程度相関がある香りもあるのでシステムに組み込むことでレコメンドを完全自動化にできると考えていましたが、完全自動化には数値的に扱えることが大前提であることを痛感しました。

私の通っている大学に香りを数値的に扱う研究をしている研究室があるらしいので今後に期待です。

提案

解決方法として、⑴ユーザーの1日の生活をクラスタリングして、相関がありそうな香り(笑)を任意にレコメンドする、⑵システムによるレコメンドをあきらめ、スペシャリストによるレコメンドにすることが考えられます。

⑴は1日の生活をクラスタリングしてそれに香りを割り当てられるのか、そして複数の相関がありそうな香りを任意にレコメンドすることはそもそもレコメンドなのか?これは最適化できているのかが気になります。

⑵はシステムがしようとしていたことをベンダー側の人間に代わるので、当初のメリットは変わりませんが、ラベルを貼ってレコメンドする必要があります。

例えば「オフィス用の香水群」「デート用香水群」「甘い香水群」など。

ラベルを貼って複数の香水を少量届けるなどのサービスが考えられ、これらは新規性があり、サービスとして成り立ちます。

しかし、工学をしている人間としては、モノを作らないのでモチベーションが上がりません(笑)

まとめ

壁にぶち当たり解決方法⑴を試みようと思うが、このサービスに多少疑念を感じ始めています。

少し触ってみて、10月11月の香りの実験補助のアルバイトで詳しいことを聴いてから判断しようと思います。

chainer-fast-neuralstyle で画像処理

ディープラーニングで画像処理をしてみたい

 OS、 プログラミング言語、ウェブ言語、機械学習、電子回路、DIYのスキルを使って 2 つのプロジェクト (後日公開予定) を進めていますが、画像処理に縁がなかったので、画風変換ライブラリ「chainer-fast-neuralstyle」でどんなものなのか試してみました。本当は GPU を用いた画風変換ライブラリを使いたかったのですが、GPU を用意できなかったので、また今度。

環境

ubuntu 18.04, python 3.7.0, cahiner, Intel corei3

使用方法

github にインストール方法が載っています。

https://github.com/dsanno/chainer-neural-style

最後にgenerate.py でインポートされる net.py の test に関する部分をすべて削除すれば実行可能になります。

写真のサイズは画像編集ソフトで 1024x768 にします。

実行

猫カフェで撮った写真

変換前

f:id:sakagutikeisuke:20180908115244j:plain

 

変換後 (model= composition)

f:id:sakagutikeisuke:20180908115256j:plain

 

この写真気に入りました。

ちなみに chainer-fast-neuralstyle は CPU で動かすので、chainer-gogh, chainer-neural-style などを GPU で動かせば、一枚の写真で鮮明に画風変換できるようになります。

 

変換後 (model= seurat)

f:id:sakagutikeisuke:20180908115306j:plain

 

model を変えればいろんな画風変換ができます。

 

まとめ

CPU で手軽に試せるライブラリでした。GPUを用意して chainer-gogh を使えばオリジナリティを出せるかもしれません。ただ cupy のインストールに Ubuntu が必要なことや GPU に CUDA 対応のものを使わなければいけないので、多少面倒です。