生成モデル「GAN」を簡単に紹介(夏季インターンシップ募集中)

 こんにちは!弊社は現在学生向けのインターンシップを募集してます。内容は最新の AI 技術を使って開発を行ってみよう!!といったものです。8/15 まで募集していますので学生の皆さまは奮って参加をお願いします!

gri.jp

 今回は、このインターンのテーマの一つである GAN (Generative Adversarial Networks: 敵対的生成ネットワーク)についてザックリ紹介します。

GAN でできること

 GAN は主に画像生成で有名になった生成モデルです。生成モデルは GAN の他にエンコーダーデコーダーを並べて変分ベイズ法によって誤差逆伝搬を可能にした VAE モデルがあります。しかし、VAE は損失に正則化項を加えたことにより、生成した画像がぼやけてしまうという欠点があります。一方で、GAN はシャープな画像が生成され、ディープラーニング界にブレイクスルーをもたらしました。
 そこから色々な派生が生まれて、ただ画像を生成するだけではなく、高解像度化・ドメイン変換・異常検知・画像再構築など多くのタスクをこなしてきました。例は以下の github になります。

github.com

GAN がやっていること

 GAN には生成器(Generator)と識別器(Discriminator)と呼ばれる二種類のモデルがあり、これらの二つのモデルが切磋琢磨しながら学習することで最終的に良質なデータを生み出す生成モデルになります。

Generator

f:id:gri-blog:20210726161452p:plain
Generator モデル
 Generator では一様ランダムに与えられたノイズを生成したいデータに変換します。ノイズは低次元のものを入れるので、アップサンプリングのニューラルネットワークになる場合が多いです。最終的にこのモデルを使用してデータを生成する形になります。

Discriminator

f:id:gri-blog:20210726161537p:plain
Discriminator モデル
 Discriminator ではデータが学習データであるか、Generator が生成したモデルであるかを判定します。モデルの構造は教師あり学習の分類で用いるようなニューラルネットワークと同じで、「本物か偽物か」を分けることになるので二値分類のモデルになります。

学習

Generator の学習

f:id:gri-blog:20210726170018p:plain
Generator の学習フロー
 Generator の目的は、学習データに限りなく似たデータを生成することです。そのために、ノイズから生成したデータが Discriminator によって「本物」と判定されるようにパラメータを最適化します。

Discriminator の学習

f:id:gri-blog:20210726165948p:plain
Discriminator の学習フロー
 Discriminator の目的は、本物と偽物を正しく判別することです。そのために、学習データは「本物」と判定されるように、Generator が生成したデータは「偽物」と判定するようにパラメータを最適化します。

収束条件

 一般的なディープラーニングでは損失が最小になるように最適化を行うため損失値が収束条件になったりしますが、 GAN では Discriminator の損失を Generator の学習では最大化するように、 Discriminator の学習では最小化するために学習を行うため収束条件としては使えません。では、どうなれば収束となるかというと、次の二つが挙げられます。

  • どのデータを入れても Discriminator が「本物」と判定する確率が 0.5 である
  • Generator が生成したデータが確かに学習に似ている

 同じようなことを言っているように見えますが、上の条件だけでは学習の途中である可能性があるので生成されたデータをしっかり見ることが大事です。

 そして、この状態になるまでには Discriminator の損失が振動する必要があります。この振動が起こっているときには Generator が Discriminator を騙すのに成功し、それを受けて Discriminator が Generator に騙されないようになることが繰り返されているので両モデルが成長している状態であるといえます。この関係が崩れてどちらかのモデルが強すぎてしまうと、学習が上手くいかなくなります(勾配消失やモード崩壊と言います)。このモデルの調整が難しく、この問題を解消するために色々な工夫がなされています(LSGAN, WGAN, α-GAN, etc...)。

 というわけで GAN の紹介でした。インターンのテーマは GAN に限らず他にも興味深いものもありますし、テーマの持ち込みも可ですので興味がある方は是非参加してみて下さい!

分析官 安井優平  

puppeteerを使ってJavascriptなサイトをクロールする

インストール

早速実践していきます
まずはインストール...

yarn add puppeteer
# or "npm i puppeteer"

インストールが完了すればnode_modulesフォルダの中に色々入ります

これでOKです

チュートリアル

githubのexampleをさらいます

// example.js
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await page.screenshot({ path: 'example.png' });

  await browser.close();
})();

実行

続きを読む

Google Spread Sheetとpython

pythonからspread sheetを操作した時のメモです
pythonのgspreadパッケージをインストールと認証ファイルを取得すれば簡単にできます

これをベースにawsのlambdaやgcpのcloud functionに乗せれば、クラウド上でスプレッドシートの操作もできるようになります

準備

こちらの内容を踏襲してます

Google Sheets APIの有効化

簡単に

  • ブラウザからGCPコンソール画面に入る
  • サイドメニューの"APIとサービス" → "ライブラリ"をClick
  • Google Sheets APIを検索し、APIを有効化
  • サイドメニューの"IAMと管理" → "サービス アカウント"をClick
  • "サービスアカウントを作成"をClick → 名前を入力し"完了"ボタンをClick(他は省略)
  • 作成されたサービスアカウントをClick → キー → "鍵を追加"でJSONで新規作成
  • ダウンロードしたjsonファイルを適当なフォルダに移動

pythonパッケージ gspread をインストール

pip install gspread
$ python -V
Python 3.9.1

$ pip freeze | grep gspread
gspread==3.7.0

実装

import gspread

servece_account = 'ダウンロードしたJSONファイルのPATH'
gc = gspread.service_account(servece_account)

上記のgcをベースにworkbookやworksheetを生やします

早見表

description code
スプレッドシートの作成 sht = gc.create('A new spreadsheet')
スプレッドシートの選択(Keyから) gc.open_by_key('Key')
スプレッドシートの選択(URLから) sht = gc.open_by_url('対象スプレッドシートのURL')
ワークシートの選択 sht.worksheet("シート名")
全セルデータの取得 val = worksheet.get_all_values()
セルの取得 1 val = worksheet.acell('B1').value
セルの取得 2 val = worksheet.cell(1, 2).value
全セルデータの削除 worksheet.clear()
対象セルの削除 sht.values_clear('C2:AB1000')
セルに書く 1 worksheet.update('B1', 'Bingo!')
セルに書く 2 worksheet.update_cell(1, 2, 'Bingo!')
セルに書く 3 worksheet.update('A1', [[1, 2], [3, 4]])

参照

higashi kunimitsu

ジョブ理論とデータサイエンス

「ジョブ理論 イノベーションを予測可能にする消費のメカニズム」クレイトン M クリステンセン (著) を読んで考えたことを書きたいと思います。


ジョブ理論とはなにか、ジョブ理論の定義はこのようにあります。

顧客はある特定の商品を購入するのではなく、進歩するために、それらを生活に引き入れるというものだ。この「進歩」のことを、顧客が片づけるべき「ジョブ」と呼び、ジョブを解決するために顧客は商品を「雇用」するという比喩的な言い方ををしている。

続きを読む

BigQueryのテーブルに可変の日付prefixを入れる

末尾に日付を入れてシャーディングすることがよくあると思います
クエリ実行時の日付を自動で入れる時のメモ

結論から

  • DECLAREで変数を宣言
  • 今日の日付を取得する関数の作成
  • 宣言した変数にテーブル名と関数をくっつける
  • EXECUTE IMMEDIATEで変数を入れたcreate文を実行する

DECLARE table_name STRING;

create temporary function getDate() AS (FORMAT_DATE("%Y%m%d",  current_date('Asia/Tokyo')));

set table_name = "{dataset-name}.{target-table-name}_" || getDate();

EXECUTE IMMEDIATE FORMAT('CREATE TABLE %s AS SELECT * FROM {dataset-name}.hoge-table', table_name);

実践

アカウントとproject

まずはloginします

gcloud auth login

存在するproject一覧

gcloud projects list

project設定

gcloud config set project {project id}

GCSアップロード

バケット作成

gsutil mb gs://bucket-for-blog

f:id:gri-blog:20210708181957p:plain

データは以下とします

# sample.csv
---
a,b,c
1,2,3
4,5,6
7,8,9
---

ファイルをバケット内にコピー

gsutil cp ./sample.csv gs://bucket-for-blog/

f:id:gri-blog:20210708182035p:plain

BigQuery初期設定

データセット作成

bq mk for-blog

sample.csvをテーブルに入れる

bq load \
    --source_format=CSV \
    --skip_leading_rows=1 \
    --autodetect \
    for_blog.sample_20210707 \
    gs://bucket-for-blog/sample.csv

前日の日付を入れたテーブルを作成しました

--autodetectによりカラムと型を推定して作成してくれます
※プロダクション環境の場合、指定するスキーマをきちんと定義してください(推奨)

f:id:gri-blog:20210708182052p:plain

シャーディングテーブル作成

では本題のクエリを実行します

sqlファイルを作成して以下のように書きました

-- sample-query.sql
DECLARE table_name STRING;
create temporary function getDate() AS (FORMAT_DATE("%Y%m%d",  current_date('Asia/Tokyo')));
set table_name = "for_blog.sample_" || getDate();

EXECUTE IMMEDIATE FORMAT('CREATE TABLE %s AS SELECT * FROM for_blog.sample_20210707', table_name);

冒頭で書いたのとほぼ同様ですね
前日テーブルを今日の日付に変えただけで、中身はただのコピーとなります

このクエリを実行します

bq query --use_legacy_sql=false < ./sample-query.sql

f:id:gri-blog:20210708182107p:plain

prefixをシャーディングとして認識してくれてますね

higashi kunimitsu

Gmailの添付ファイルをpythonで取得する

課題

データ連携のツールとしてmailのケースがたまにあります
それを予測データとして他のツールにimportしたりすると思いますが

  • ローカルにダウンロード
  • ダウンロードしたデータをDBにimport と人作業の部分が発生してしまうのでそれをどうにかしたい

その課題から、mailに添付されたファイルを自動で取得できるようした時のメモ

事前準備

今回Gmailアカウントを対象としてます Gmailは自前で作成したコードから接続を試みると"安全性の低いアプリ"と判断されてrejectするので まずは安全性の低いアプリの許可を有効にする必要がある

Google安全性の低いアプリのアクセスページに入りログインして許可にします

f:id:gri-blog:20210707125630p:plain

使用する時だけこれをONにしたいのですが、この有効化手順の自動はstackoverflowのここ見る限りでは難しそうです

今回実行したpythonのバージョンは3.9.1となります

実行

必要なモジュール

import imaplib
import base64
import os
import email
import datetime as dt
  • 全て標準ライブラリになります。pipなどでの追加インストール作業は不要です
  • imaplibはemailプロトコルimap standardのpackage
  • base64はASCIIへの変換、逆変換するものとしてimportしてます

次にmailのプロトコルを使った設定

mail = imaplib.IMAP4_SSL('imap.gmail.com', 993)

ログイン

email_user = 'email-address@gmail.com'
email_pass = 'email-password'

mail.login(email_user, email_pass)

エラーが起きなければ接続ができています Inbox内のメールから対象ファイルを取得したいので場所を指定します

mail.select('Inbox')

Inbox内の対象ファイルを検索します
今回は送信元のアドレス、期間で絞り込みます

t_addr = '送信元メールアドレス'

t_date = '2021-07-01'
t_date_format = dt.datetime.strptime(t_date, '%Y-%m-%d')

search_option = f'(FROM "{t_addr}" SENTSINCE "{t_date_format.strftime("%d-%b-%Y")}")'
type, data = mail.search(None, search_option)

t_date, t_date_formatは対象となる日付を指定し、それを日付型にしてます
また、searchが認識する日付型に再度変換してます('2021-07-01' -> '01-Jul-2021')
RFC-822に沿った日付型だとエラー。年月日までの型じゃないとダメみたいです

searchの最初の引数はcharsetとなり、特に指定する文字形式がなければNoneにします
次の引数でフィルタをかけます。最低1つの条件が必要となってます
imaplib.IMAP4.search

受け取ったtype, dataはこんな感じ

OK [b'477 1149 1522 1724 1954']

typeは成功したかどうか、成功した場合dataにはlist型でメッセージ番号がスペース区切りで入っています

これを直近のメッセージだけ取得する場合は下記のように書きます

t_number = data[0].split()[-1]  # b'1954'

で、今後は受け取った番号のメッセージ内容を取得するためfetchを使います

type, data = mail.fetch(t_number, '(RFC822)')

受け取ったdataはlist型内にtupleとしてメッセージのコンテンツが入っています
またデータはbyte型なのでここでemailモジュールを使ってパースします

email_message = email.message_from_bytes(data[0][1])

パースしたメッセージを順に読み込んでいき、添付されたfileを検索
取得したらそれをローカルファイルに書き込みます

for part in email_message.walk():
    file_name = part.get_filename()
    if not file_name:
        continue
    fns = file_name.split('?')
    output_file_name = base64.b64decode(fns[-2]).decode(fns[1])
    with open(f'{os.getcwd()}/{output_file_name}', 'wb') as f:
        f.write(part.get_payload(decode=True))

get_filename()で添付ファイル名を取得 file_nameは場合によってこんな感じになっていると思います

file_name: =?ISO-2022-JP?B?nanikashiranomojiretsu=?=

これは下記の形式になっており

=?文字セット?エンコード方式?エンコード文字列?=

文字セット、エンコード方式から文字列をデコードする必要があるんですね

?で区切ったリストから文字セットとエンコード文字列(ファイル名)を取得したあと人が読める文字にデコード
これをアウトプットのファイル名(添付ファイルと同名)にし、payloadからファイルコンテンツを取得して書き込んでます

エンコードされていないファイルの場合はfile_nameをそのまま使用します

いかがでしたでしょうか?メールのプロトコルって歴史があるためか、今のapiとかと比べると取得が大変なんですねー
ちなみに今回は受信メールを対象にしてますが、送信になるとまたプロトコルが変わりますよー

参照

IMAP4 プロトコルクライアント
Gmailで「安全性の低いアプリ」がブロックされた場合の対処方法

higashi kunimitsu

ForecastFlow機能追加(20210705リリース)

ForecastFlowの20210705リリースによるアップデートで、予測モデルを構築する際、詳細設定(Advanced Settings)による自動機能が3つ追加されました。

f:id:gri-blog:20210706161309j:plain

  • UnderSampling(アンダーサンプリング): 訓練タスクのモデルタイプがClassification分類(データ上は二値分類)の際、2値の件数が同数になるように、ランダムにアンダーサンプリングされます。"Enable Undersampling Feature"のチェックボックスをオンにすることで、アンダーサンプリングが実施されます。なお、テストデータや解釈に対する内容に関して後述します。

  • Hyperparameter(ハイパーパラメタ): デフォルトで試行回数(Number of Turnings)が20回になっておりますが、試行回数を減らすことで、訓練時間の短縮が見込まれます。なお、試行回数を減らすと予測精度が低下する傾向にあります。

  • Model Splitting(モデル分割): 以前からモデル分割機能は存在しましたが、カテゴリ特徴量の値ごとにモデルを自動分割します("The column to split the model"にてカテゴリ特徴量を選択します)。選択できるカテゴリ特徴量の値は、最大15種類までの特徴量になります。限定を解除するためには、カスタムプランへの契約変更が必要になりますので、お問い合わせください

f:id:gri-blog:20210706161615j:plain

詳細設定の注意事項

今回のアップデートの注意事項といたしまして、自動アンダーサンプリングと自動モデル分割を同時に実行できません。この機能追加のリリースは近い将来に実施予定です。

もう1つの注意事項として、自動アンダーサンプリングの機能が追加されましたが、次回のアップデート(2021/7/26週を予定)まで慎重にご利用いただきたい点を下記に記載いたします。

アンダーサンプリングを利用するシナリオは、不均衡なターゲットデータに対して予測精度を向上させる予測モデルを構築することです。現バージョンのForecastFlowの予測精度レポート(Performance Report)は、二値問題では閾値を0.5にした上で、予測精度を算出しています。今回のアップデートでは、訓練データのみアンダーサンプリングしており、テストデータに対してはアンダーサンプリングを行わずに解釈しやすい数値での感度分析(Sensitivity Analysis)を演算しています。この点に起因して、先ほどの閾値0.5では、アンダーサンプリングをした際、実際は予測精度が向上しているにも関わらず、予測精度が減少したように見えるケースが発生します。次回のアップデートで、閾値の最適化機能を追加し、アンダーサンプリングを適切な予測精度と共に確認できるようにします。

f:id:gri-blog:20210706164539j:plain

念のため、通常の予測モデル構築でのテストデータ分割を説明します。アップロードしたデータが1,000件で陽性率が10%であったケースを考えてみます。訓練データとテストデータを7:3で分割した場合、陽性率が変わらないまま、件数が7:3に分割されます。訓練モデルをテストデータに当てはめ、事前的な予測精度を算出します。不均衡なデータの場合、良い予測精度になりずらいため、アンダーアンプリングの手法を試みます。

f:id:gri-blog:20210706165232j:plain

今回の機能追加のアンダーサンプリングでは、訓練データ700件に対してアンダーサンプリングを行い、True 70件、False 70件の1:1に補正したデータで、訓練モデルを構築し、テストデータ300件で精度検証を行います。その際、先ほどの方法と比較して、予測精度を検証する際、陽性率がかなり異なるため、予測スコアの閾値を最適化する必要があり、この機能に関して追加が必要になります。

f:id:gri-blog:20210706170251j:plain

なお、アンダーサンプリングにより訓練された予測モデルは予測精度が向上するが、推論スコアなどにはバイアスがかかることが知られています。今回のアップデートにて、推論スコアにキャリブレーション(補正)をかけて、より現実的な推論スコアにしています。例えば、感度分析(Sensitivity Plot)に関しても、より現実に近い数値に補正しています。この補正はProbability Calibrationとして知られ、現在進行形で研究が進んでいる分野になります。この解説は、別記事で行います。

古幡征史