Briswell Tech Blog

ブリスウェルのテックブログです

Pythonで江戸パワポ作成

江戸の古地図

夜な夜な江戸の古地図をながめるのが最近の和みです。

ふと、古地図で移転前の弊社オフィス(@恵比寿)周辺を眺めていると、ドラマの撮影でよく使われる「タコ公園」前を流れる渋谷川は、当時も同じように流れていました。

渋谷川を調べてみると

春の小川は さらさら行くよ〜♪

この歌のモデルになっているらしい。その昔、歌のように川の水はとてもきれいで、蛍もいたようです。

また、タコ公園周辺には、大きなお屋敷(森越中赤穂藩下屋敷)もありました。恵比寿駅東口の五差路も当時から存在しています。何かワクワクしませんか?

江戸庶民の生活

さて、江戸時代の地図に想いを寄せていると、その当時の生活はどのようなものであったのか気になってきました。

www.php.co.jp

こちらの本を今読んでいるのですが、江戸庶民の生活模様が、収入やモノの値段からうかがい知れてとても興味深いです。宵越しの銭を持たず物事に執着しないのが「江戸っ子」の美学と言われています。隣近所が一つの家族のようにワイガヤで楽しく助け合いながら暮らしていたのでしょう。当時の情景が目に浮かんできます。

江戸パワポ

と、ここでテックブログなので... 一つPythonネタをご紹介します。

下図のように、Microsoft PowerPointのテンプレファイルに、新しいスライドを追加し

  1. タイトルテキスト
  2. 円グラフ
  3. テキストボックス

を挿入することができます。

f:id:KenjiU:20200628204157p:plain

データ引用:
中江 克己(2003/8/1) | お江戸の意外な「モノ」の値段 物価から見える江戸っ子の生活模様(PHP文庫) | 位置No.176/2899

1. ライブラリの定義
from pptx import Presentation
from pptx.chart.data import ChartData
from pptx.enum.chart import XL_CHART_TYPE, XL_LEGEND_POSITION, XL_LABEL_POSITION
from pptx.util import Cm, Pt

以下の「python-pptx」ライブラリを使用します。 python-pptx.readthedocs.io

2. テンプレとするパワポを指定
prs = Presentation('edo_expenses_template.pptx')
3. 空のスライドの挿入
title_only_slide_layout = prs.slide_layouts[1]
slide = prs.slides.add_slide(title_only_slide_layout)
shapes = slide.shapes
4. タイトルテキストの挿入
shapes.title.text = '江戸時代のある大工さんの家計'
5. 表の挿入
# 表のデータを定義
name_objects = ['支出項目','匁']
name_expenses = ['家賃', '飯米', '塩・味噌・油・薪炭', '道具・家具', '衣服費', '音信・祭礼・布施']
val_expenses = [120, 354, 700, 120, 120, 100]

# 表の行数と列数
rows = 7
cols = 2

# 表を挿入する位置
top_table = Cm(6)
left_table = Cm(3)

# 表の幅と高さ
width_table = Cm(14)
height_table = Cm(7)
table = shapes.add_table(rows, cols, left_table, top_table, width_table, height_table).table

# 表のヘッダーの定義
table.cell(0, 0).text = name_objects[0]
table.cell(0, 1).text = name_objects[1]

# 表のボディの定義
for index in range(len(name_expenses)):
  table.cell(index+1, 0).text = name_expenses[index]
  table.cell(index+1, 1).text = str(val_expenses[index])
6. 円グラフの挿入
# グラフを挿入する位置
top_graph = Cm(14)
left_graph = Cm(5)

# グラフの幅と高さ
width_graph = Cm(21)
height_graph = Cm(12)

# グラフのデータを定義
total = sum(val_expenses)
def calc_double(n):
    return n / total
val_expenses_percent = list(map(calc_double, val_expenses))

chart_data = ChartData()
chart_data.categories = name_expenses
chart_data.add_series('Pie', val_expenses_percent)

graphic_frame = slide.shapes.add_chart(
    XL_CHART_TYPE.PIE, top_graph, left_graph, width_graph, height_graph, chart_data
    )
chart = graphic_frame.chart

# グラフのプロパティを定義
chart.has_legend = True
chart.legend.position = XL_LEGEND_POSITION.BOTTOM
chart.legend.include_in_layout = False
chart.plots[0].has_data_labels = True
data_labels = chart.plots[0].data_labels
data_labels.number_format = '0%'
data_labels.position = XL_LABEL_POSITION.OUTSIDE_END
7. テキストボックスの挿入
# テキストの定義
text = '※銀一匁は現代で約1,250円です。'

# テキストボックスを挿入する位置
top_text = Cm(14)
left_text = Cm(3)

# テキストボックスの幅と高さ
width_text = Cm(5)
height_text = Cm(2)

# フォントサイズ
text_font = 20

# テキストボックスの定義
text_box = slide.shapes.add_textbox(left_text, top_text, width_text, height_text)
text_box.text = text
text_box.text_frame.add_paragraph().font.size = Pt(text_font)
8. ファイル保存
prs.save('edo_expenses.pptx')

以上です。
AI学習モデルの予測精度やデータ分析の報告書作成などにも利用できそうです。

株式会社ブリスウェル

行き先掲示板IoT化計画(仮)

こんにちは大澤です. こちらの記事(クラスタリング勉強会 - Briswell Tech Blog)でAI勉強会を実施した大澤です.

  • 特技はマジック(クロースアップ)

  • 好きなものは紅茶とチョコレート(チョコレートスペシャリストの資格保有)

  • 苦手なものは犬・猫

  • 最近の趣味はカリグラフィの動画を見ること

・・・

さて,新型コロナウィルスの騒ぎがあり,ブリスウェルでは3月からリモートワークを実施しています.7月からは様子をみながら徐々に出社(時差出勤)の方向性になっていますが,引き続きリモートのメンバーもいます. 通勤時間が0になるという最大のメリットを享受していましたが,4ヶ月も続くと不便な点も出てきます.

例えばリモートだと相手の状態がわかりません.

出社してれば「今MTG中かな」「もう帰っちゃったかな?」というのが分かります.(わからないときもあります)

昼休憩に入るときも,リモート時はチャットで休憩に入る旨を伝えています.

なんとなぁく不便だなぁと感じていたので,ブリスウェルのIoT担当として何かソリューションを考えようと思い立ちました. これはつまり,古き良き「行き先掲示板」をIoT化してあげたら良いのかも知れません.とするとこんなものはいかがでしょう.

f:id:kyoshi0000:20200627202610p:plain

ステータス管理ボックスと名付けました.決してふざけているわけではありません.

説明しますと,これは手のひらサイズの箱(or ブロック)のデバイスです.例えば「出社」の面を上にするとその人のステータスは「出社」となり,「MTG」の面を上にするとステータスが「MTG」となります. このデバイスを各メンバーが持ち,それぞれのステータスデータをサーバに送ってあげることで,各メンバーのステータスを確認できるじゃないか!というわけです. これを実現するためには,どの面が上になっているかを知る必要があります.これは加速度センサをデバイスに仕込んであげればできそうです. また,データをサーバーに投げるので,ネットに繋いであげる必要もあります.

なんとなくできる気がしてきたので,早速作ってみました.

【用意したもの】

  • 押し入れに眠っていたWiFiモジュール「DSP-WROOM-02」(ESPr Developer)
  • 早速買った3軸デジタル加速度センサモジュール「ADXL345」

ESP-WROOM-02arduino IDEを使用して開発できるので非常に楽です.

また,加速度センサはアナログ出力ではなく,デジタル出力でないといけません. (ESP-WROOM-02にはアナログ入力ポートが1つしか無いので,3軸のアナログデータを取得するのが難しいためです)

【作ってみる】

こんな感じで接続して,arduinoIDEでプログラムを書き込んであげると… f:id:kyoshi0000:20200627204941j:plain

なんと加速度が取得できます.X軸,Y軸の値は小さいですが,Z軸の値が大きく出ていますね.つまりデバイスは上向きであることがわかります. f:id:kyoshi0000:20200627205049p:plain

次にESPをWiFiに接続してセンサデータをサーバに投げます. PHPで受け手側のプログラムをなんとなく書き,ローカルサーバを立ち上げ,センサデータを投げるプログラムをESPに書き込みます. ブラウザを立ち上げて,作ったデバイスの向きを色々変えてみます.すると… f:id:kyoshi0000:20200627205433p:plain

出社!



この向きだと… f:id:kyoshi0000:20200627205533j:plain

f:id:kyoshi0000:20200627205742p:plain

お昼!  …ん??

f:id:kyoshi0000:20200627205840p:plain

うーん,向きに応じて異なるデータを送ることはできていますが,表示の仕方に工夫が必要ですね…この辺りは他のメンバーの方が得意そうです.

表示はどうにかしたいですが,やりたいことはできました. こういうのは未完成でも基本的な機能ができた時点で人目につく場に出してフィードバックをもらうべきだと偉い人に教わりました. いかがでしょうか.

ステータスを管理してメンバーで共有するだけならそういうWEBサービスを使えばいいだけですが,リアルの世界の動作と紐付けられるのはIoTの強みだと思います.

なかなか外出できない土日を有意義に過ごすことができました.

システム開発プロジェクト成功の秘訣 ー 提案編 ー

東京は梅雨入りしてジメジメしてますが、いかがお過ごしでしょうか?

新型コロナの感染者もまだまだ収束していないため、ブリスウェルではリモートワークを継続しているメンバーも多いです。

さて、今日はシステム開発プロジェクト成功の秘訣と題して、書かせていただきます。

私自身、システム開発の仕事に携わって20年以上経ちますが、とても難しく奥深い仕事だと未だに感じています。

今までの経験から、システム開発を成功させるために重要だと考えていることについて、提案編と題して私の考え方をご紹介させていただきます。

ブリスウェルの主力事業はシステム開発サービスで、お客様からシステム構築の依頼を受けて、システムを開発して納品する仕事をしています。

システム開発を外部の会社に委託する場合、発注サイドと受注サイドがいて、システムの完成まで両者が協力し合い、完成後もより良いものに育てていく必要があります。

単に売って終わりというわけではなく、契約後も協力してアウトプットを創り出していく必要のあるビジネスです。

ブリスウェルのような受注者サイドとしては、

・お客様のビジネスや業務の流れ

・既存システムの仕組みやデータの流れ

・関連する外部システム

など様々な情報が不足した状態でお客様との最初のコンタクトとなることがあります。

そのような状態でもなんとか競合他社との戦いを勝ち抜き発注をいただくために色々と努力をすることになります。

受注サイドがどのような観点で提案を作成していくのかという情報は、発注サイドにとっても良い開発会社を選定する上での助けになるのではないかと思っています。

それでは具体的に見て行きましょう。

1)お客様の見えない要求を嗅ぎ分ける

f:id:yamagoochi:20200622130445j:plain
見えない要求を嗅ぎ分ける

ヒアリングやRFPを元に、過去の経験から機能一覧を推測で策定する

この能力が会社の提案力ということになると思います

全体の流れを押さえるためのQAや詳細なQAを繰り返しながら、お客様のビジネスや業務、既存システムや外部連携システムとの連携の仕組みなどを想像していきます

限られた時間で100%を把握することは不可能なので、根拠を持った上で必要だと思われる全ての機能を洗い出すことが重要です

2)要求を数字に変換する

f:id:yamagoochi:20200622130552j:plain
要求を数字に変換する

重要なのは画面数、機能数、帳票数、IF数など数字や難易度に基づいて工数を見積ることです

お客様からのハイレベルな要求を具体的な数値レベルに落とし込めることがシステム開発を請け負う上でとても大切な能力だと考えています

ふわっとした営業トークではなく、具体的に完成形をイメージできるレベルまで詳細化できることが付加価値だと思っています

また、お客様になぜそのような実装方針なのかを質問された場合に、根拠をすぐに回答できる状態であることがとても大切です

3)工数と金額を明示する

f:id:yamagoochi:20200622130623j:plain
工数と金額を明示する

開発規模から考えられるリスクを考慮した見積を算出する

ある程度機能単位での工数や費用を提示することで、価格感をお客様と共有できることになります

これはその後のスコープ変更時やリリース後の追加改修時の見積根拠が発注者と共有できるため無用な価格交渉や不信感を排除できると考えています

逆に言うと、不明確な部分が多い場合は開発会社側はある程度リスクを積むことになります

発注者側はできるだけ詳細な情報を提供して見積金額のバラツキが出にくくなるように配慮することがとても大切です

一定規模以上の案件の場合、リスク要因を把握しきれないことが多いため、要件定義終了後に開発フェーズ以降を再提案する旨を合意した方が良いと考えています

4)差別化

f:id:yamagoochi:20200622130647j:plain
差別化

提案時には自分たちが差別化できるポイントをセールストークの中心に据えることが重要です

顧客のことを深く理解することができることが伝わるととても良いですし、逆に顧客に懸念されているポイントを強みに変えられるとアピール力が高まります

例えば弊社では、あるプロジェクトの提案の際に以下の3つのポイントを差別化ポイントとして提案をしたことがあります

1 豊富な過去の経験(大規模プロジェクト実績や発注者側のプロジェクトリーダー経験がある)

 ⇒発注者の立場を理解できるという安心感

2 業界向けパッケージの活用(業界ノウハウがある)

 ⇒担当者の要求を正確に吸い上げられるという信頼感

3 オフショア開発(徹底した品質管理体制)

 ⇒ただ安いだけではなく品質もしっかりしているという安心感

お客様やプロジェクトの内容によってセールスポイントの中心をどこに持っているかは変わりますが、基本的な部分は共通していると考えています

5)プロジェクトリーダーが全てを背負えること

f:id:yamagoochi:20200622130712j:plain
プロジェクトリーダーが全てを背負えること

最終的にお客様がパートナー選定という大きな決断をする場合、やはり信頼できる人なのかどうかがとても重要だと感じています

いかなる質問にも誠実に回答する姿勢がとても大切です

金額交渉においても上司にお伺いを立てるような姿勢はできるだけ控え、オーナーシップを発揮できることを示した方が信頼感がアップすると思います

プロジェクトリーダーとしてオーナーシップを発揮できるレベルになるには相当の努力と経験と覚悟が必要です (まだまだ私自身も一人前とは言えないのですが)

そういう人が世の中に増えると良いな そのきっかけをブリスウェルで作れると良いな と思いながら経営をしています

また、業界的にはとても重要な感覚ではあるのですが、リスク回避的な態度はできるだけ見せない方が良いと思っています

とはいえ、お客様とリスクの存在を共有し、できればリスクに対する対策案を提示できると尚良いです

以上がシステム開発案件の提案を行う際に、私が大切にしていることになります

いよいよプロジェクトがスタートした後の流れ、要件定義編についても近いうちに記事を書こうと思っています

皆様のお役に少しでも立つことができたら幸いです!

音声データのノイズ除去

時間や場所にとらわれずに柔軟な働き方を実現する「Web会議」。すっかり身近になりましたね。

Web会議は、必要な時にその場ですぐに会議を開催することができるので、情報共有や意思決定を迅速に行うことができます。日程調整もしやすいので、参加者の予定を合わせやすいですね。ただ、ブレストのような自由に意見を出し合う類いの打合せは、ちょっと向いてないかなと最近感じます。座ったままPCと睨めっこ状態だと、なかなか良いアイデアも生まれてきません。これも慣れなのかしら。

ここでWeb会議あるある、です。

1. ミュートしたまま話続ける
相槌や意見を言い続けたのに、ミュートだったと気付いた時は虚しさ半端ないです。

2. 思わぬ来客
宅配便でーす!ご飯まだー?にゃあ。
日常が見えて、微笑ましいですね。

3. 雑音トラブル
カタカタカタ…ガタンゴトンガタンゴトン…どんがらがっしゃーん!
なかなか自分では気付かないことが多いです。

などなど...
どうでしょう。みなさんも思い当たるふしがあるかと思います。

さて、今回は「3. 雑音トラブル」をPythonで解決してみましょう!

ノイズ除去処理の流れ

  1. 高速フーリエ変換FFT)を用いて、ノイズデータの周波数成分を取得。あるアルゴリズムにより、ノイズと見なすしきい値を計算する。

  2. 高速フーリエ変換FFT)を用いて、ノイズを含む音声データの周波数成分を取得。1のしきい値によりノイズの部分をマスクする。

  3. 音声として復元する。

が大まかな処理の流れとなります。 pypi.org 今回は、こちらの「noisereduce」ライブラリを使用します。簡単にノイズ除去を試すことができます。

1. ライブラリの定義

import IPython
from scipy.io import wavfile
import noisereduce as nr
import soundfile as sf
from noisereduce.generate_noise import band_limited_noise
import matplotlib.pyplot as plt

2. 音声データの読み込み

data, rate = sf.read('voice.wav')
fig, ax = plt.subplots(figsize=(20,3))
ax.plot(data)

f:id:KenjiU:20200607215236p:plain
音声データ

3. ノイズデータの読み込み

noise_data, noise_rate = sf.read('noise.wav')
IPython.display.Audio(data=noise_data, rate=noise_rate)

fig, ax = plt.subplots(figsize=(20,4))
ax.plot(noise_data)

f:id:KenjiU:20200607215240p:plain
ノイズデータ

4. ノイズを含んだ音声データを生成

snr = 2 # signal to noise ratio
noise_clip = noise_data/snr
audio_clip = data + noise_clip
IPython.display.Audio(data=audio_clip, rate=noise_rate)

fig, ax = plt.subplots(figsize=(20,4))
ax.plot(audio_clip)

f:id:KenjiU:20200607215247p:plain
ノイズを含んだ音声データ

5. ノイズを除去し音声として復元

なんと以下のたったの一行でノイズ除去が実現できてしまいます。

noise_reduced = nr.reduce_noise(audio_clip=audio_clip, noise_clip=noise_clip, verbose=True)

f:id:KenjiU:20200607215254p:plain
ノイズ
f:id:KenjiU:20200607215257p:plain
ノイズと見なすしきい値を計算
f:id:KenjiU:20200607215312p:plain
入力音声データ
f:id:KenjiU:20200607215318p:plain
ノイズの部分をマスク
f:id:KenjiU:20200607215333p:plain
音声として復元

IPython.display.Audio(data=noise_reduced, rate=rate)

どうでしょう。完璧とは言えませんが、雑音トラブル無事解決!?

fig, ax = plt.subplots(figsize=(20,3))
ax.plot(noise_reduced)

f:id:KenjiU:20200607215336p:plain
ノイズ除去済み音声データ

今回は以上です!
1/fゆらぎのBGMを聞いていたら眠くなってきました( *˘ω˘)スヤァ…

Elastic Beanstalk config ファイルでどハマりしたお話

お疲れ様です。
みなさまいかがお過ごしでしょうか。

コロナウィルスにより、大変な世の中になってしまい、今後どうなっていくのか不安に思っています。

弊社は2月末よりテレワークとなりました。
一部は出社している日もあるようですが、基本的にはもうみんなの顔を忘れている頃だと思います。
私はお家時間が増えたので、FODを契約し、のだめカンタービレのドラマと映画を一気にみました。
今クラシックを聞きながら書いています。
一曲もわかりません。

本題です。
私は2 ~ 3年ほど前からElasticBeanstalk + CircleCI or GitLabCI or GitHubAction という構成を多く使用しています。
色々な構成内容をconfigファイルに記載しておき、
developとproductionをブランチによって自動で切り替えたり、環境構築を人依存しないようにしております。

近頃スタートしたプロジェクトの開発環境を構築しようと、以前のプロジェクトから色々コピーしました。
ハマりました。
今回はNode.js + nginx 環境です。

http → https のリダイレクトを nginx で設定しています。

files:
 /etc/nginx/conf.d/redirect.conf:
 mode: "000644"
 owner: root
 group: root
 content: |
# Redirect HTTP To HTTPS
 server {
 listen 81;
 rewrite ^ https://$host$request_uri permanent;
 }

こんな感じのファイルを
.ebextensions/redirect.config

として置いておけば、あとはElastic Beanstalk君がやってくれていました。

...ところが新しく作った環境だとリダイレクトされない...  

...ファイルの記載方法が悪いのか...  

...ログみても何も残っていない...  

...とりあえず、SSH Key作って接続して中身みてみよう...

あれ...
/etc/nginx/conf.d/redirect.conf
作られてねーじゃん。

なんで無視するの?嫌われた?
という壁にぶち当たりました。

色々調べていくと...
https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/platforms-linux-extend.html

どうやら Linux
というプラットフォームでは nginx などの設定は

.platform/nginx/conf.d

にそのままの記載方法

server {
 listen 81;
 rewrite ^ https://$host$request_uri permanent;
}

これを custom.conf などに記載するように共通化されたみたいでした。

確かに元々のプロジェクト達は
Node.js running on 64bit Amazon Linux/4.14.1

今回は
Node.js 12 running on 64bit Amazon Linux 2/5.0.1

 でした。
これか!
となりました。(何かログ出してくれると助かったけど...)

AWSの進化は早いので、統一して全てのプロジェクトあげていこう!
と思いました。

他の困った方の役に少しでも立てれば幸いです。

Python × Selenium で自動化

元素周期表の覚え方「水兵リーベ僕の船...」懐かしいですね。
その元素記号の34番目は「Se」(Selenium)です。

一方、ITにおけるSelenium

  1. Webページにアクセスしてログイン

  2. 対象データを検索

  3. 必要な情報を入力して登録

というような、普段Webブラウザで行っている操作を自動化することができます。
PythonでもこのSeleniumを利用することができます。

最新ニュース記事取得

最近気になるニュースは?

就活の面接でも良く聞かれます。選んだニュースにより、その人の感性や価値観、人柄、知的好奇心が分かるので、効果的な質問だと思います。

さて、今回は最新ニュース記事の取得・収集を自動化する方法をご紹介します。(スクレイピングと言われているものです)

1時間毎にGoogleの「AI」最新ニュース記事を取得。それをSlackに投稿し、Excelに保存する。
の流れです。皆さんもサクッと試してみましょう。

1. 初期設定

pipコマンドを使って、Seleniumをインストールします。
$ pip install selenium

Google Chrome版のWebDriverをダウンロードします。
ChromeDriver - WebDriver for Chrome

2. ライブラリの定義

ここからはプログラミングです。
PythonSeleniumを使うために必要なライブラリを定義します。

  • Slackに投稿
  • Excelに保存
  • 定期実行

これらの処理のために必要なライブラリもあわせて定義します。

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys

import requests
import datetime
import time
import cv2
import openpyxl
import schedule

3. WebDriverのオプション設定

Google Chrome版のWebDriverの設定です。headlessモードにすると、画面表示なしで動作します。自分のPC作業に影響せずに裏で動いてくれるので助かります。

DRIVER_PATH = './chromedriver'
options = Options()
options.add_argument('--headless')
driver = webdriver.Chrome(executable_path=DRIVER_PATH, options=options)

4. 定数の定義

検索キーを変更すれば、別のニュース記事を取得できます。

SearchKey = 'AI' #ニュースの検索キー
Token = 'XXXX-XXXX-XXXX-XXXX' #Slackで取得したトークン
Channel = 'XXXX' #SlackのチャンネルID
Excelfile = 'LatestNews.xlsx' #Excelファイル名

5. メイン処理

URL指定で最初からニュース一覧の画面に遷移させることもできますが、テンプレートとして他でも流用できるようにあえて検索キーを入力しての画面遷移としております!

def job():
  # Googleのページを開く
  driver.get("https://www.google.co.jp/")

  # 検索Boxのelementを取得
  search_box = driver.find_element_by_class_name("gLFyf")

  # 検索Boxにキーを入力
  search_box.send_keys(SearchKey)

  # Enterキーを入力
  search_box.send_keys(Keys.ENTER)

  # Google検索結果画面のニュースタブのelementを取得
  link_news = driver.find_element_by_class_name("q")

  # ニュースタブをクリック
  link_news.click()

  # 最新ニュース記事のリンクのelementを取得
  link_news_latest = driver.find_element_by_class_name("l")

  # 最新ニュース記事のリンクをクリック
  link_news_latest.click()

  # 最新ニュース記事画面の幅と高さを取得(全画面のスクショを撮るため)
  page_width = driver.execute_script('return document.body.scrollWidth')
  page_height = driver.execute_script('return document.body.scrollHeight')

  # 最新ニュース記事画面の幅と高さをセット
  driver.set_window_size(page_width, page_height)

  # 画面読み込みのため待機
  time.sleep(20)

  # 現在日時取得
  dt_now = datetime.datetime.now()
  
  # スクショのファイル名定義
  screenshot_path = "Pictures/" + str(dt_now) + ".png"

  # スクショ保存
  driver.save_screenshot(screenshot_path)

  # スクショのPNG画像を圧縮
  img = cv2.imread(screenshot_path)
  cv2.imwrite(screenshot_path, img, [cv2.IMWRITE_PNG_COMPRESSION, 9])

  # 画面タイトルを取得
  cur_url_title = driver.title

  # 画面URLを取得
  cur_url = driver.current_url

  # Slackに投稿(画面タイトル, 画面URL, スクショ)
  files = {'file': open(screenshot_path, 'rb')}
  param = {
    'token':Token,
    'channels':Channel,
    'initial_comment': SearchKey + "最新ニュース" + "\n\n" + cur_url_title + "\n\n" + cur_url,
    'title': screenshot_path
  }
  requests.post(url="https://slack.com/api/files.upload",params=param, files=files)

  # Excelの最終行に追記(時間, 画面タイトル, 画面URL, 検索キー)
  wb=openpyxl.load_workbook(Excelfile)
  sheet = wb.active
  max_row = sheet.max_row
   
  list = [dt_now, cur_url_title, cur_url, SearchKey]
  for index, item in enumerate(list):
    sheet.cell(row=max_row+1,column=index+1).value = item
  wb.save(Excelfile)

6. 定期実行処理

scheduleライブラリを使用すると手軽にジョブの設定ができます。

# 3分毎に実行
# schedule.every(3).minutes.do(job)
# 1時間毎に実行
schedule.every().hour.do(job)

while True:
  schedule.run_pending()
  time.sleep(1)

以上です!シンプルですね。

最後に

今回は、最新ニュース記事取得(スクレイピング)を例としてご紹介しましたが、WebシステムのUIテスト自動化にも使えます。画面遷移や、項目が多い入力フォームの検証にはもってこいです。単純な繰り返し作業はSeleniumにお任せしちゃいましょう!

株式会社ブリスウェル

キュウリ収穫量の可視化

キュウリを植えたらキュウリと別の物ができると思うな。人は自分の植えたものを収穫するのである。
二宮尊徳(金次郎)

変わらなければ生き残れない
ドラスティックに何かを変えなければ...
そんな危機感が日々日々強くなっていきます。

ただやはりキュウリからはキュウリである。自分自身に今あるものを育てて、いかに美味しく生き生きとしたものにしていくか。こんな時だからこそしっかりと学び、またやってくる旬の時期に備えたいですね。

とキュウリキュウリ言っていますが、僕はキュウリが大好きです。浅漬け、ピリ辛、梅あえ、シンプルなもろきゅう&味噌マヨもたまりません。宮崎県のキュウリの冷汁も大好きです。

今回はキュウリでいきましょう!

f:id:KenjiU:20200504130909p:plain

キュウリの収穫量を可視化してみました。なんとPythonによるWebアプリで実現しています。

PythonでWebアプリ作成

Pythonといえば機械学習ディープラーニング用。そんな風に考えていらっしゃる方も多いかと思います。しかし、Pythonには様々なライブラリが存在しており、実はWebアプリも作成することが可能です。

では、コードを見ていきましょう。

1. ライブラリの定義

定義しているDashPython用のWebアプリを作成するためのフレームワークです。Bootstrap(HTML, CSS, JavaScript フレームワーク)やPlotly(グラフライブラリ)を使うことができます。

import dash
import dash_bootstrap_components as dbc
import dash_html_components as html
import dash_core_components as dcc
import numpy as np
import pandas as pd
import plotly.graph_objects as pgo

# Bootstrapスタイルシートをリンク
app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])

2. データの取得

キュウリの収穫量データと都道府県の緯度経度データを読み込みます。
以下のサイトのデータを使用いたしました。

きゅうり(キュウリ・胡瓜)の産地|全国、都道府県別生産量(収穫量)の推移/グラフ/地図/一覧表|統計データ・ランキング|家勉キッズ

【みんなの知識 ちょっと便利帳】都道府県庁所在地 緯度経度データ - 各都市からの方位地図 - 10進数/60進数での座標・世界測地系(WGS84)

# きゅうりの都道府県別収穫量データ(CSVファイル)を読み込む
# 引用: ieben.net | きゅうりの生産量(収穫量)
# https://ieben.net/data/production-vegetables/japan-tdfk/k-kyuuri.html
ccb = pd.read_csv('cucumber_jpn.csv')

# 都道府県の緯度経度データ(Excelファイル)を読み込む
# 引用: みんなの知識 ちょっと便利帳 | 都道府県庁所在地 緯度経度データ
# https://www.benricho.org/chimei/latlng_data.html
ccb_latlng = pd.read_excel("latlng_data.xls", header=4)
ccb_latlng = ccb_latlng.drop(ccb_latlng.columns[[0,2,3,4,7]], axis=1).rename(columns={'Unnamed: 1': '都道府県'})
ccb_latlng = ccb_latlng.head(47)

3. データをグラフ表示用に加工

2で読み込んだデータを加工します。

# 収穫量分布バブルチャート用
# 「きゅうりの都道府県別収穫量データ」と「都道府県の緯度経度データ」をマージ
ccb_merge = pd.merge(ccb, ccb_latlng, on='都道府県')
# バブルチャートにカーソルをあてた時に表示されるテキストを定義
ccb_merge['notes'] = np.nan
for i in range (len(ccb_merge)):
  ccb_merge['notes'][i] = ccb_merge['都道府県'][i] + ' / ' + str(ccb_merge['収穫量'][i]) + 't' + ' / ' + str(ccb_merge['順位'][i]) + '位'

# 収穫量トップ20グラフ用
ccb_prep = ccb.sort_values("収穫量",ascending=False).head(20)
ccb_prep = ccb_prep.sort_values("収穫量")

4. 画面表示処理

各エリアのサイズや色やテキストなどを仕様に従い定義します。とてもシンプルですね。

app.layout = dbc.Container(
[
  # 画面のタイトルエリア
  dbc.Row(
  [
    dbc.Col(
    html.H1("キュウリの収穫量グラフ"),
    style = {
    "size": "30px",
    "backgroundcolor": "#fffcdb",
    "color": "#00a95f",
    "textAlign": "left",
    }
    )
  ],
  ),
  # グラフのタイトルエリア
  dbc.Row(
  [
    # 左グラフのタイトル
    dbc.Col(
    html.H4("収穫量分布"),
    width = 7,
    style = {
      "height": "100%",
      "backgroundcolor": "white",
      "textAlign": "left",
      "padding":"10px"
      },
    ),
    # 右グラフのタイトル
    dbc.Col(
    html.H4("収穫量トップ20"),
    width = 5,
    style = {
      "height": "100%",
      "backgroundcolor": "white",
      "textAlign": "left",
      "padding":"10px"
      },
    ),
  ],
  ),
  # グラフエリア
  dbc.Row(
  [
    # 左グラフ
    dbc.Col(
    dcc.Graph(
    id = 'JpnMap',
    figure = {
    'data' : [
      pgo.Scattergeo(
      lat = ccb_merge["緯度"],
      lon = ccb_merge["経度"],
      marker = dict(
        color = 'rgb(0, 169, 95)', #バブルチャートの色
        size = ccb_merge['収穫量']/1500+5, #バブルチャートのサイズ
        opacity = 0.7 #バブルチャートの透明度
        ),
      hovertext = ccb_merge['notes'], #カーソルをあてた時に表示されるテキスト
      hoverinfo = "text"
      )
      ],
    'layout' : pgo.Layout(
      width = 600,
      height = 500,
      template="plotly_dark", #ダークモード
      margin = {'b':5,'l':5,'r':5,'t':5},
      geo = dict(
        resolution = 50,
        landcolor = 'white', #陸地の色
        lataxis = dict(
          range = [25, 47], #地図表示範囲(緯度)
        ),
        lonaxis = dict(
          range = [126, 150], #地図表示範囲(経度)
        ),
      )
    )
    }
    ),
    ),
    # 右グラフ    
    dbc.Col(
    dcc.Graph(
    id = 'Pref',
    figure = {
    'data' : [ 
      pgo.Bar(
      x=ccb_prep['収穫量'],
      y=ccb_prep['都道府県'], 
      orientation='h' #横棒グラフ
      ),
      ],
    'layout' : pgo.Layout(
      width = 400,
      height = 500,
      template = "plotly_dark", #ダークモード
      margin = {'b': 5, 'l': 5, 'r': 5, 't': 5},
      xaxis_title = "収穫量",
      yaxis_title = "都道府県"
      )
      }
    ),
    ),
  ],
  ),
],
)

5. アプリ起動処理

最後にWebアプリ起動処理です。Dashはホットリロード機能を持っており、コードに変更があった場合に、自動でブラウザをリフレッシュします。

# アプリを起動
if __name__ == "__main__":
  app.run_server(debug=True)

最後に

キュウリの生育適温は20〜25℃。暖かくなり始めた5月の連休頃が植え付け時期となります。夏の生育期のキュウリは1日3cm以上も大きくなります。実家の庭で、朝小さかったキュウリが昼過ぎにはすっかり大きくなっていて、びっくりしたこともありました。ベランダ菜園始めようかしら。

AIと芸術

ついつい最新ニュースが気になってしまう今日この頃。外出自粛ムードの三連休、皆さんいかがお過ごしでしょうか。

運動不足解消のため、僕はご当地版ラジオ体操で毎回笑いながら体操してます。世間では、あの爆発的なムーブメントを巻き起こしたビリーズブートキャンプが再燃しているようです。入隊しようかしら。

家トレも良いですが、ゆったりと音楽を聞いたり、映画を観たり、本を読んだりして過ごしている方も多いかと思います。
なんとそれらの芸術的な分野までも「AI」が担う時代が来るかもしれません。

今回はクリエイティブなことが不得意と言われてきた「AI」について、最近の芸術分野での活躍ぶりをまとめてみました。

音楽

2019年の第70回NHK紅白歌合戦で「AI美空ひばり」が大いに注目を集めました。

僕は歌声を聞いたとたん思わず涙が出てしまいました。子供の頃よくテレビから聞こえてきたあの歌声がふとよみがえってきたというのと、AIでここまでできるようになったのかという衝撃からだと思います。

www.yamaha.com

ヤマハさんの「VOCALOID:AI」(ディープラーニングを使った歌声合成技術)を用いて実現しているとのこと。

学習用データの美空ひばりさんの歌声ですが、美空ひばりさんは歌声のみのレコーディングはされていなかったそうで、伴奏が含まれた歌声データから伴奏部分を取り除く作業が容易ではなかったようです。

データの前処理はとても難しくコストもかかりますが「命」と言われるくらい学習には欠かせない工程になります。

www.itmedia.co.jp

こちらのITmediaさんの記事に、学習モデルについての説明があります。

 開発したシステムでは、複数の学習モデルを組み合わせて歌声を合成する。与えられた楽譜を読み込んで、音程を決めるモデルや発音のタイミングを決めるモデルといった歌声の特徴を作るものと、それらを組み合わせてコントロールするモデルや、最終的な波形を合成するモデルなどを段階的に使う。素片接続とは大きく異なる技術だ。

歌声合成のため、このような学習モデルを複数組み合わせているとは... 驚きの技術です。

「AI」と付くと、あたかも「AI」が自分で音楽を創り出すように感じますが、実際はインプットのデータ(学習用データ)をどうするか、どのようなモデルを用意するか、どのようなアウトプットを期待するかなど「人間」の創造的作業がとても重要になってきます。

漫画

AIと人間によって制作された手塚治虫さんの新作漫画「ぱいどん」が2月27日(木)発売の「モーニング」に掲載されました。

発売直後に購入しましたが、近未来の技術と人間が描かれており、シナリオ、絵、セリフどれも自然で読みやすく続編がとても気になる内容でした。はたして、どの部分をAIが担っているのでしょうか。

robotstart.info

こちらのロボスタさんの記事によると、AIはプロット(設定とあらすじ)とキャラクター(顔)を担当しているとのこと。

  1. プロット

    今回の作品はAIと人間の協業によるもので、ストーリーとマンガの書き起こしのほとんどは人間が行っている。AIが担当したのはまずは作品のプロット(設定とあらすじ)。手塚治虫氏が描いた漫画のストーリーを学習したAIがプロットだけを提示。それを元にスタッフが検討しながらストーリーを作り上げた。

  2. キャラクター

    NVIDIAが開発している人間の顔生成のシステムを応用。膨大な人間の顔画像を元にAIが人間の顔を生成する技術(おそらくGAN)のAIモデルをこのプロジェクトに活用することを決めた。人間の顔生成システムに手塚氏の漫画のキャラクターを追加学習する「転移学習」を行うと、成果がみるみる向上。その中から「ぱいどん」のイメージにぴったりの顔を採用した。

インプット(学習用データ)として、手塚治虫氏の作品データを読み込ませたり、はたまた人間の顔も利用したり、アウトプットについても人が選定して組み合わせていくなど、AIと人間の共同作業と言えるでしょう。人間の創造的作業をいかにデータ化(数値化)して学習用データとして利用できるかが難しいところですね。

俳句

空蝉や 揺れる草木を しかと抱き

こちらは祖母が詠んだ俳句です。昔、祖母の家の額縁に飾っており今でも心に残っております。つい最近、「空蝉」とは、古語の「現人(うつしおみ)」が訛ったもので「生きている人間の世界」を表すことを知り、地に足をつけて生きていこうという思いが強くなりました。

この感性が求められる俳句の作成についても、AIが挑戦しています。

AI俳句協会さんのサイトにAIが作成した俳句が載せられています。AIがどういう意図でその季語や言葉を選んだのか想像すると何か楽しいです。人間には生みだせない意外性が素敵ですね。

気になったAI俳句を一点ご紹介。

初便り 携帯電話 閉ざすのみ

ガラケーなのかなと、微笑ましい気持ちになります。

最後に

現状のAIでは、作品を勝手に生み出すことはできません。人間が、適切なデータを学習させたり、様々な条件を指定したり、評価・調整をしたりして、作品が生み出されます。

ただ、AIは過去のデータを大量に学習することができ、色々なパターンを試すことができます。その結果、人間には生み出せない何かを生み出せたり、人間が気付けなかったことを発見することがあるかもしれません。

人間が創造的作業を行うツールの一つとして、AIを上手く活用することができれば、AIならではの面白い共同作品が生まれてくるでしょう。

OpenAI Gymで強化学習

何かを始めようと思ったとき、まずは「それは前例のあることだろうか」と調べたり、他の人の意見を聞いたりすることがあるかと思います。

過去に同じような事例があると分かった場合、仲間を見つけたような安心感がでてきますね。確かにその事例を参考にすることで行動がしやすくなり、失敗するリスクを減らすことができます。

とはいえ、前例ばかり気にするのはよくありません。前例がないと行動できないのであれば、新しいものを世に送り出すことができません。前例がないからこそ、うまくいけば成功事例として注目されるわけです。

と誰よりも慎重派ビビリ属の僕が申し上げてしまいました。ただ「AI」ならばどうでしょうか。強化学習と呼ばれる手法により、失敗を恐れることなく試行錯誤を繰り返し、成功へと導いていきます。

では今回は、AI強化学習の手法を通して、新しいことへのチャレンジのコツを学んでいきましょう。

強化学習とは

強化学習」は、赤ちゃんが失敗を繰り返しながら歩き方を習得していくのと似てます。

www.youtube.com

こちらは、僕の大好きな「物理エンジンくん」さんの強化学習シミューレーション動画です。

  • 重心が前進する
  • 頭がある高さの幅にある

を「報酬」にして学習していますね。
強化学習を理解するには、「状態」「行動」「報酬」という3つの概念が重要です。

  1. 状態: 環境が今どのような状態か
  2. 行動: その状態での実際の行動
  3. 報酬: その行動によって獲得したスコア

赤ちゃんの歩き方習得を例にすると、「強化学習」では赤ちゃんのことを「エージェント」と言います。赤ちゃん(エージェント)は、まだ歩くことができない状態(=1. 状態)で歩こうとチャレンジし(=2. 行動)、それによってどれだけ歩けたか(=3. 報酬)がより大きくなるように頑張ります。

つまり、「強化学習」におけるエージェントは、「1. 状態」において何かしらの「2. 行動」を起こし、その行動から得られる「3. 報酬」を獲得するという処理を何度も行い、報酬の合計が一番大きくなるように学習していきます。

www.youtube.com

こちらは、もう一つの強化学習動画です。シュールですね。大好きです。

OpenAI Gymとは

さて、「物理エンジンくん」ほどのシミュレーションはできませんが、OpenAI Gymというオープンソース強化学習シミュレーション用プラットフォームを利用して、強化学習を試してみます。

山登りチャレンジ

OpenAI Gymの古典的な強化学習環境であるMountainCar-v0で山登りチャレンジをしましょう。

f:id:KenjiU:20200217185336g:plain
学習初期

2つの山の間にいる車(エージェント)が、前後に勢いをつけ、坂を登ろうとします。車が右の山の頂上(位置0.5)にあるゴールまで到達できたら、1エピソード終了となります。200ステップ内にゴールまで到達できなかった場合もタイムオーバーで1エビソード終了です。車は、速度が「0」、位置は「-0.6」〜「-0.4」のランダム位置から開始します。

報酬はステップ毎に「-1」(マイナスの報酬=罰)が与えられ、例えば200ステップ内にゴールできずタイムオーバーとなった場合は、トータル報酬は「-200」になります。強化学習は、このもらえる報酬ができるだけ大きくなるように行動する方法を学んでいきます。

今回は「Q学習」という強化学習アルゴリズムを使用します。

1. ライブラリと定数の定義

定数の中の「時間割引率」とは、すぐにもらえる小さい報酬を優先するか、将来にもらえる大きい報酬を優先するかを定義します。せっかち度ですね。「0」に近いほど将来の報酬は無視されて、「1」に近いほど将来の報酬が重視されます。

import gym
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
mpl.use('Agg') # matplotlibがAnti-Grain Geometry (AGG) を使う指定

# 定数
alpha = 0.2 # 学習係数
gamma = 0.99 # 時間割引率(0〜1)
epsilon = 0.002 # ε-グリーディ法のεの確率
num_divisions = 40 # 離散化時の分割数

2. 連続値から離散値に変換

連続値とは連続して無限に流れている「時間」のようなもの。また、離散値とは「人数」のように数えることができるものです。連続値である「位置」と「速度」を離散値に変換します。

def get_state(_observation):
    env_low = env.observation_space.low # 位置と速度の最小値
    env_high = env.observation_space.high # 位置と速度の最大値
    env_dx = (env_high - env_low) / num_divisions # 分割
    position = int((_observation[0] - env_low[0])/env_dx[0]) # 位置の離散値
    velocity = int((_observation[1] - env_low[1])/env_dx[1]) # 速度の離散値
    return position, velocity

3. Q関数を更新

経験(行動、状態、次の状態、報酬)に応じてQ関数を更新します。これにより、エージェントは時間の経過とともに、最適な行動をとれるようになります。

Q関数は以下のように表します。

Q(S_{t},a_{t})←Q(S_{t},a_{t})+α[r_{t+1}+γ\max_a Q(S_{t+1},a)-Q(S_{t},a_{t})]

  • S_{t}:時間tの時の状態
  • a_{t}:時間tの時の行動
  • α:学習係数
  • r_{t+1}S_{t+1}に遷移したときに得る報酬
  • γ:時間割引率
  • max_a Q(S_{t+1},a):次ステップの価値を最大化するQ関数
def update_q_table(_q_table, _action,  _observation, _next_observation, _reward, _episode):
    next_position, next_velocity = get_state(_next_observation)
    next_max_q_value = max(_q_table[next_position][next_velocity]) # 次ステップの価値を最大化するQ関数
    position, velocity = get_state(_observation)
    q_value = _q_table[position][velocity][_action]

    _q_table[position][velocity][_action] = q_value + alpha * (_reward + gamma * next_max_q_value - q_value)

    return _q_table

4. ε-グリーディ法

「ε-グリーディ法」という手法を用いて、現在の状態に応じた行動を選択するようにします。1-εの確率で最良の行動、εの確率でランダム行動を選択します。

現状に甘んじず、さらなる最適解を求めてランダムな行動を恐れることなくとるところが素敵ですね。

def get_action(_env, _q_table, _observation, _episode):
    if np.random.uniform(0, 1) > epsilon:
        position, velocity = get_state(observation)
        _action = np.argmax(_q_table[position][velocity])
    else:
        _action = np.random.choice([0, 1, 2])
    return _action

5. 動画保存

山登りチャレンジ結果を動画として保存します。

from JSAnimation.IPython_display import display_animation
from matplotlib import animation
from IPython.display import display

def display_frames_as_gif(frames):
    plt.figure(figsize=(frames[0].shape[1]/72.0, frames[0].shape[0]/72.0), dpi=72)
    patch = plt.imshow(frames[0])
    plt.axis('off')

    def animate(i):
       patch.set_data(frames[i])

    anim = animation.FuncAnimation(plt.gcf(), animate, frames=len(frames), interval=50)
    anim.save('movie_mountain_car.mp4')
    display(display_animation(anim, default_mode='loop'))

6. 学習実行

では、5000エピソードで学習を実行してみましょう。

if __name__ == '__main__':

    # 環境の生成
    env = gym.make('MountainCar-v0')

    # 初期化
    is_episode_final = False
    q_table = np.zeros((40, 40, 3))
    observation = env.reset()
    rewards = []
    history = []
    frames = []
    fig = plt.figure()

    # 学習
    for episode in range(5000):

        total_reward = 0
        observation = env.reset()
        
        if episode == 4999:
            is_episode_final = True

        for _ in range(200):
            # ε-グリーディ法で行動選択
            action = get_action(env, q_table, observation, episode)

            # 行動により、次の状態・報酬・ゲーム終了フラグを取得
            next_observation, reward, done, _ = env.step(action)

            # Q関数を更新
            q_table = update_q_table(q_table, action, observation, next_observation, reward, episode)
            total_reward += reward

            observation = next_observation

            # 最終エピソードの画面を描画
            if is_episode_final is True:
                frames.append(env.render(mode='rgb_array'))
            
            # ゲーム終了フラグがTrueになったら1エピソード終了
            if done:
                  if episode%100 == 0:
                      # ログ出力
                      print('episode: {}, total_reward: {}'.format(episode, total_reward))
                  rewards.append(total_reward)
                  history.append(total_reward)
                  plt.plot(history)
                  break

        if is_episode_final is True:
            # グラフを保存
            fig.savefig("img.png")
            # 動画を保存
            display_frames_as_gif(frames)

7. 実行結果

f:id:KenjiU:20200217185342g:plain
5000エピソード目

5000エピソード目を実行時の動画です。最初は全く登れる気配がなかったのに、強化学習の結果、悠々と登りきっています。

f:id:KenjiU:20200217184200p:plain
トータル報酬の推移

1〜5000エピソードのトータル報酬の推移グラフです。1000エピソードぐらいまでは、トータル報酬は「-200」となっており、200ステップ内で登りきれていませんが、1000エピソード以降はエピソードを積むにつれてより少ないステップで登れるようになっています。知的ですね。

最後に

現在、弊社も新規サービス立ち上げのために試行錯誤しております。強化学習のように、実施した結果をしっかりと評価、反省して次の行動につなげ、成功したとしてもその前例にとらわれず、更なる高みへ向けて果敢にチャレンジしていきたいと思います!

今回、参考にさせていただいた記事は以下です。ありがとうございました。
OpenAI Gym 入門 - Qiita
OpenAI Gym入門 / Q学習|npaka|note

AIのメリット・デメリット

映画「AI崩壊」が公開されましたね。早速観てきました。

AIとはどういうものなのか、またAIが日常生活に深く浸透してきた場合どのような問題が発生しうるか、がよく分かるかと思います。AI vs 人間ではなく、AIを取り巻く人間を中心に描かれており、AI時代に人間がなすべきことは何なのか、を考えさせられました。大沢たかおさん演じる桐生浩介の走りにも脱帽です。

これ以上は、ネタバレになってしまいますのでやめておきます。

さて、今回は、AIのメリット・デメリットについて書きます。僕たちも、AI製品の企画・開発を日々進めていますが、一度立ち止まって再認識したいと思います。

AIのメリット

①自動化による業務効率化

AIを活用することで、単調で同じ動作が繰り返される作業について、人間が実施するよりも早く正確にこなすことが可能になります。しかも、24時間365日動き続けることが可能です。

「RPA(ロボティック・プロセス・オートメーション)」が注目を集めて久しいですね。定型化できるPC業務について、手順を登録するだけで正確に自動処理を行うことができます。効率化のプロフェッショナルとも言えます。

ただ、いざRPAを導入したものの、十分に活用しきれないケースもあるようです。例えば、残業が多い部署の業務を自動化しようとRPAを導入したのに、残業の原因である業務が、人の判断、思考に依存するもの(例:顧客との関係性によって対応を変えなければならないもの)であれば意味がありません。

自動化できる業務を正しく見極める必要があります。

②安全性の向上

危険を伴う作業や、人間が立ち入ることができない場所での作業をAIに任せることができます。福島第一原子力発電所では、事故の安定化および廃炉の推進のために、ロボットが活用されています。

また、AIにより、道路のひび割れなどインフラの劣化や、機械の故障を自動的に検知することによって、事故を事前に防ぐことができ、適切なタイミングでメンテナンスを行うことができます。

転倒などの「ふらつき検知」、モノの「置き忘れ検知」など、個人の安全性に貢献する活用法も考えられています。

③創造的機会の創出

単調な作業をAIに置き換えることによって、人間はよりクリエイティブな作業や、人との高度なコミュニケーション力が求められている仕事に集中できる環境が生まれます。ただ、単純な作業とはいえ、いかにして効率的にこなすかを考えたり、やり遂げた後の達成感があったりするなど、AIに置き換えることで幸せかというとちょっと懐疑的です。また、以下のデメリットに記載していますが雇用の減少につながる可能性があります。

AIのデメリット

①雇用の減少

定型業務などがAIに置き換わることにより、人間が今まで行っていた業務量が減少し、雇用の減少がおきるのではと大きく懸念されています。 映画「AI崩壊」でも「AIに仕事が奪われる」ことを問題視しています。

②依存性

人間がAIに依存し、何事もAIの判断に委ねることになった場合、人間の判断能力は著しく低下してしまうでしょう。AIに意見を聞くぐらいの関係性が望ましいのかもしれません。

また、人間社会とAIが密接な関係になった場合、AIの管理にトラブルが発生すると、AIシステムと紐付けされている全ての環境に影響が出ることになります。もしも会社のメイン業務がAIと連携していれば、問題が解消するまで会社が機能しなくなる可能性もあります。そのため、万が一に備えたバックアップ体制を整えるなどのリスクマネジメントが重要となります。

③責任の所在

AIが問題を起こした場合、責任の所在をどうするか、という問題があります。「AIがそう判断したから」ではすまされません。法整備も必要ですが、判断、思考内容に透明性があり十分に検証可能なAIも求められます。

まとめ

今回は、AIについてのメリット・デメリットについてまとめました。

十分に検討が必要な課題もありますが、AIによって、確実に私たちの生活は便利になるでしょう。ただ、AIは自ら新しいものを生み出せません。いかにAIを使いこなし、私たちの生活を豊かで幸せなものにしていくかは人間次第です。これからは、AIのメリット、デメリットをよく理解して、うまく共存していくことが求められます。

あっと驚くサービスを弊社から出せるように頑張ります!

株式会社ブリスウェル