The Littlest JupyterHubのインストール

はじめに

JupyterHubは複数のユーザにJupyterを提供するために最適な環境です。
(要件によってはColaboratoryCloud AI Notebooksが良いと思います)

JupyterHubには二つのディストリビューションがあり、自前で構築する前にこれらを検討するべきです。
https://jupyterhub.readthedocs.io/en/stable/

ユーザが100人以下の場合、The Littlest JupyterHubが推奨されます。これは単一のマシンに構築することを想定しています。

https://tljh.jupyter.org/en/latest/

GCPにインストールする場合

基本的にはこちらのマニュアルに従えば問題ありません。
https://tljh.jupyter.org/en/latest/install/google.html

ただし、記載のものではスタートアップスクリプトが動作せず、下記のように書き換えが必要でした。

1
2
3
4
#!/bin/bash
curl https://raw.githubusercontent.com/jupyterhub/the-littlest-jupyterhub/master/bootstrap/bootstrap.py \
| sudo python3 - \
--admin <admin-user-name>

設定

設定はtljh-configコマンドを通じて行います。例えばパスワード認証に一定回数失敗した場合のアカウントロックを設定しましょう。

1
2
3
4
sudo tljh-config set auth.type nativeauthenticator.NativeAuthenticator
sudo tljh-config set auth.NativeAuthenticator.allowed_failed_logins 3
sudo tljh-config set auth.NativeAuthenticator.seconds_before_next_try 120
sudo tljh-config reload

最後にreloadすることで設定が反映されますが、接続中のユーザに影響はありません。

HTTPS化

こちらにLet's Encryptを用いた設定方法が記載されています。
https://tljh.jupyter.org/en/latest/howto/admin/https.html

記事情報

  • 投稿日:2020年7月3日
  • 最終更新日:2020年7月3日

GCE(VM)へのコンテナのデプロイ

コマンドがなかなか見つからなかったので残しておきます。公式リファレンスを参考にしました。

https://cloud.google.com/compute/docs/containers/deploying-containers?hl=ja

Docker Hubから利用する際などの参考にしてください。

Apache

gcloud compute instances create-with-container httpd-vm
–container-image docker.io/httpd:2.4
–tags http-server

Nginx

gcloud compute instances create-with-container nginx-vm
–container-image gcr.io/cloud-marketplace/google/nginx1:latest
–tags http-server

JupyterHub

gcloud compute instances create-with-container jh-vm
–container-image docker.io/jupyterhub/jupyterhub:latest
–tags http-server

記事情報

  • 投稿日:2020年7月2日
  • 最終更新日:2020年7月2日

メルフィルタバンクを理解する

はじめに

Kaggle Free Sound Audio Tagging 2019で学ぶ音声処理ではKaggleコンペとその解法を題材に音声処理について解説しています。この記事は、メルスペクトログラムの計算中に出てきたメルフィルタバンクについて解説します。

librosa.feature.melspectrogram

librosa.feature.melspectrogramのコードを読むで出てきた通り、librosa.feature.melspectrogramは引数として音声を受け取ることも、スペクトログラムを受け取ることもできます。

内部ではスペクトログラムに対して、メルフィルタバンクと呼ばれるものをかけています。

1
2
3
mel_basis = librosa.filters.mel(sr, n_fft=2048)
S = np.abs(librosa.stft(y))**2
melspec = np.dot(mel_basis, S)

(見やすくするために、下図では対数を取っています。)

メルフィルタバンク

メルフィルタバンクは、複数のバンドパスフィルタをメル尺度上で等間隔となるように配置しています。また周波数が高いほど、バンド幅が広くなっていることがわかります。これは上の図でも確認できます。

librosaでは以下のように計算できます。

1
mel_basis = librosa.filters.mel(sr, n_fft=2048)

メルフィルタバンクの効果

通常のスペクトログラムと、メルスペクトログラムを比較してみましょう。メルスペクトラムの方が高周波が強調され見やすくなっていると思います。(いずれも対数を取っています。)

記事情報

  • 投稿日:2020年7月1日
  • 最終更新日:2020年7月1日

librosa.feature.melspectrogramのコードを読む

はじめに

Kaggle Free Sound Audio Tagging 2019で学ぶ音声処理ではKaggleコンペとその解法を題材に音声処理について解説しています。この記事は、紹介している解法にも出てきたメルスペクトログラムの計算について掘り下げます。

librosa.feature.melspectrogram

引数

公式ドキュメントから引用しています。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
y:np.ndarray [shape=(n,)] or None
audio time-series

sr:number > 0 [scalar]
sampling rate of y

S:np.ndarray [shape=(d, t)]
spectrogram

n_fft:int > 0 [scalar]
length of the FFT window

hop_length:int > 0 [scalar]
number of samples between successive frames. See librosa.core.stft

power:float > 0 [scalar]
Exponent for the magnitude melspectrogram. e.g., 1 for energy, 2 for power, etc.

kwargs:additional keyword arguments
Mel filter bank parameters. See librosa.filters.mel for details.

y

音声の時系列信号です。

sr

サンプリングレートを表します。

S

音声(y)を引数に取ることもできますが、スペクトログラムを事前に計算して渡すこともできます。

以下のコードで結果が等しくなることを確認できます。

1
2
3
4
melspec = librosa.feature.melspectrogram(y, sr)
S = np.abs(librosa.stft(y))**2 # スペクトログラムを計算する
melspec_s = librosa.feature.melspectrogram(S=S)
np.array_equal(melspec, melspec_s) # arrayが等しいことを確認

n_fft

FFT窓の幅を表します。

hop_length

ステップ幅を表します。

power

1でエネルギー、2でパワーとなります。デフォルト値は2です。

kwargs

メルフィルタバンクのパラメータを与えることができます。メルフィルタバンクの詳細についてはメルフィルタバンクを理解するで解説しています。

記事情報

  • 投稿日:2020年6月30日
  • 最終更新日:2020年7月1日

Kaggle Free Sound Audio Tagging 2019で学ぶ音声処理

はじめに

機械学習の題材を探してみると画像処理・言語処理は多く見つかるものの、音声処理はあまり多くありません。ビジネスのニーズとしては(比較的)小さいからでしょうか。今回はKaggleのコンペティションFree Sound Audio Tagging 2019を使って、音声処理について紹介します。

Free Sound Audio Tagging 2019

https://www.kaggle.com/c/freesound-audio-tagging-2019

音声をマルチラベル分類するタスクです。ラベルは例えば

  • Bark
  • Raindrop
  • Finger_snapping
  • Run

などがあります。

音声処理に馴染みがない方は、このタスクをどう解いていけば良いかなかなか思い浮かばないかもしれません。

そういう時は優勝者のソリューションに学びましょう。

優勝者のソリューション

https://www.kaggle.com/c/freesound-audio-tagging-2019/discussion/95924

  • 特徴量: ログスケールのメルスペクトログラム
    メルスペクトログラムは音声処理特有の特徴量です。
  • モデル: CNN(注意機構、スキップコネクション、auxiliary classifiers)
    モデルについてはCNNを利用しており、機械学習に触れたことがある方なら特に問題ないでしょう。
  • データ拡張: SpecAugment, Mixup
    SpecAugmentは音声処理特有のデータ拡張手法です。
  • アンサンブル
    Kaggleではスコアの底上げのためにアンサンブルがよく用いられ、特に音声処理に限った話ではないです。

細かな違いはありますが、他の上位入賞者のソリューションも似ています。

特徴量: ログスケールのメルスペクトログラム

特徴量を作成する前に実際に音声を聞いてみましょう。Jupyterでは音声を聞くこともできます。

なお、本記事のコードは全てGitHubにアップロードしています。

1
2
3
import IPython.display as ipd
fname = 'input/0006ae4e.wav' # Bark(吠える声)のサンプルです。
ipd.Audio(fname)

メルスペクトログラムの計算のためにlibrosaを用います。librosaは音声解析用途のPythonライブラリです。
https://github.com/librosa/librosa

librosaで音声ファイルをロードします。

1
2
import librosa
y, sr = librosa.load('input/0006ae4e.wav')

yは音声の時系列信号、srはサンプリングレートを表します。

これをそのまま受け取り、メルスペクトログラムを計算する関数が用意されています。librosa.feature.melspectrogramで何をしているのかの詳細についてはlibrosa.feature.melspectrogramのコードを読むに書きました。

1
melspec = librosa.feature.melspectrogram(y, sr)

可視化してみましょう。

1
2
3
4
import librosa.display
import matplotlib.pyplot as plt
librosa.display.specshow(melspec)
plt.show()

なんだか暗くてよくわかりません。ログスケールに変換します。

1
log_melspec = librosa.power_to_db(melspec)
1
2
librosa.display.specshow(log_melspec)
plt.show()

今度は特徴がはっきり取れました。これならCNNの入力として使えそうですね。

データ拡張手法

追記予定

記事情報

  • 投稿日:2020年6月29日
  • 最終更新日:2020年7月1日

Apache JMeterの基本的な使い方

はじめに

Apache JMeterはWebアプリケーションのパフォーマンス測定および負荷テストを行うことができるOSSです。

インストール

  1. 事前にJavaの環境構築が必要です。

  2. Macの場合brewでインストールするのが簡単です。

1
brew install jmeter

操作方法

  1. ターミナルでjmeterとし、起動します。
  1. 言語の設定をします。

Options > Choose Language > Japanese

  1. スレッドグループの追加をします。

編集 > 追加 > Threads(Users) > スレッドグループ

必要に応じて

  • スレッド数
  • ループ回数

などを設定します。

  1. サンプラーを追加します。

スレッドグループを右クリックして、

追加 > サンプラー > HTTPリクエスト

  1. HTTPリクエストの情報を埋める。

画像のように、

  • プロトコル
  • IP
  • ポート番号
    などを埋めてください。
  1. 実行する。
    GUI上部の再生ボタンを押すと、リクエストが開始されます。ただし、実行前にテスト計画を保存する必要があります。

おわりに

以上がApache JMeterの基本的な使い方になります。

記事情報

  • 投稿日:2020年6月28日
  • 最終更新日:2020年6月28日

ABC172

はじめに

この記事では、AtCoder Beginer Contest 172のA~D問題を解説します。

A - Calc

https://atcoder.jp/contests/abc172/tasks/abc172_a
Pythonの累乗は第一引数と第二引数が共に整数であれば、整数を返すので問題ありません。

1
2
a = int(input())
print (a+a**2+a**3)

B - Minor Change

https://atcoder.jp/contests/abc172/tasks/abc172_b

一文字ずつ判定をしていけば良いです。

1
2
3
4
5
6
S = input()
T = input()
ans = 0
for s,t in zip(S,T):
ans += (s!=t)
print (ans)

C - Tsundoku

https://atcoder.jp/contests/abc172/tasks/abc172_c

累積和を用いることでO(M+N)で求めることができます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import itertools
N,M,K = map(int,input().split())
A = [0]+list(map(int,input().split()))
B = [0]+list(map(int,input().split()))
SA = list(itertools.accumulate(A))
SB = list(itertools.accumulate(B))
ans = 0
j = len(B)-1
for i in range(len(SA)):
while(j>=0):
if SA[i] + SB[j] <= K:
ans = max(ans,i+j)
break
j-=1
print (ans)

D - Sum of Divisors

https://atcoder.jp/contests/abc172/tasks/abc172_d

公式解説の解法の通りに実装すれば、O(N)です。

1
2
3
4
5
6
N = int(input())
ans = 0
for X in range(1, N+1):
Y = N // X
ans += Y * (Y + 1) // 2 * X
print(ans)

二重ループ内の計算が軽いため、PyPyであれば以下のコードでもACできます。

1
2
3
4
5
6
N = int(input())
ans = 0
for i in range(1, N+1):
for j in range(i, N+1, i):
ans += j
print(ans)

関連記事

過去のABC解説記事です。

  • ABC171
    • A-E問題を解いています。
  • ABC170
    • A-D問題を解いています。
  • ABC169
    • A-F問題を解いています。
  • ABC168
    • A-E問題を解いています。
  • ABC167
    • A-E問題を解いています。
  • ABC166
    • A-F問題を解いています。
  • ABC165
    • A-F問題を解いています。
  • ABC164
    • A-E問題を解いています。
  • ABC163
    • A-D問題を解いています。
  • ABC162
    • A-E問題を解いています。

記事情報

  • 投稿日:2020年6月27日
  • 最終更新日:2020年6月27日

Ubuntu cronの設定

cronのインストール

1
apt-get install cron

cronの実行、状態確認、停止

1
2
3
service cron start
service cron status
service cron stop

cronの設定

1
2
cp /etc/crontab /etc/cron.d/cron
vi /etc/cron.d/cron

例えば以下のように追記します。

1
*/1 * * * *     root    echo "hello" >> /home/hoge/hello.txt

cronの再起動

service cron restart

確認

1分ごとに、hello.txtに追記されればOKです。

記事情報

  • 投稿日:2020年6月26日
  • 最終更新日:2020年6月26日

JupyterHubの設定

アカウントロック

セキュリティの観点で一定回数パスワードを間違えた際にアカウントをロックしたい場合があります。

JupyterHubのデフォルトの認証はPAMです。
https://jupyterhub.readthedocs.io/en/stable/getting-started/authenticators-users-basics.html
PAMを使うことで、OSのシステム上のアカウントを認証に用いることができます。

そのため、アカウントロックの設定はJupyterHubではなくLinux側で行うことになります。

筆者の環境はJupyterHubの公式のDockerコンテナを利用しており、ディストリビューションはUbuntu18.04でしたのでその前提で進めます。

以下のファイルを編集します。

1
/etc/pam.d/common-auth

以下のような設定が確認できるはずです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#
# /etc/pam.d/common-auth - authentication settings common to all services
#
# This file is included from other service-specific PAM config files,
# and should contain a list of the authentication modules that define
# the central authentication scheme for use on the system
# (e.g., /etc/shadow, LDAP, Kerberos, etc.). The default is to use the
# traditional Unix authentication mechanisms.
#
# As of pam 1.0.1-6, this file is managed by pam-auth-update by default.
# To take advantage of this, it is recommended that you configure any
# local modules either before or after the default block, and use
# pam-auth-update to manage selection of other modules. See
# pam-auth-update(8) for details.

# here are the per-package modules (the "Primary" block)
auth [success=1 default=ignore] pam_unix.so nullok_secure
# here's the fallback if no module succeeds
auth requisite pam_deny.so
# prime the stack with a positive return value if there isn't one already;
# this avoids us returning an error just because nothing sets a success code
# since the modules above will each just jump around
auth required pam_permit.so
# and here are more per-package modules (the "Additional" block)
# end of pam-auth-update config

ここに、例えば5回失敗したらロック、ただし30秒で解除の場合以下のような行を挿入します。

1
auth    required        pam_tally2.so deny=5 unlock_time=30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#
# /etc/pam.d/common-auth - authentication settings common to all services
#
# This file is included from other service-specific PAM config files,
# and should contain a list of the authentication modules that define
# the central authentication scheme for use on the system
# (e.g., /etc/shadow, LDAP, Kerberos, etc.). The default is to use the
# traditional Unix authentication mechanisms.
#
# As of pam 1.0.1-6, this file is managed by pam-auth-update by default.
# To take advantage of this, it is recommended that you configure any
# local modules either before or after the default block, and use
# pam-auth-update to manage selection of other modules. See
# pam-auth-update(8) for details.

# here are the per-package modules (the "Primary" block)
auth required pam_tally2.so deny=5 unlock_time=30
auth [success=1 default=ignore] pam_unix.so nullok_secure
# here's the fallback if no module succeeds
auth requisite pam_deny.so
# prime the stack with a positive return value if there isn't one already;
# this avoids us returning an error just because nothing sets a success code
# since the modules above will each just jump around
auth required pam_permit.so
# and here are more per-package modules (the "Additional" block)
# end of pam-auth-update config

失敗の数は下記のコマンドで確認できます。

1
pam_tally2 -u [USERNAME]

実際にログインを失敗させて、回数が増えるかを確認してみましょう。

アカウントのロック解除は下記のコマンドです。

1
pam_tally2 -r -u [USERNAME]

HTTPヘッダの設定

HTTPヘッダもjupyterhub_config.pyを編集すれば良い。

試しに脆弱性対策として、いくつか設定を行ってみます。

vi jupyterhub_config.py

1
2
3
4
5
c.JupyterHub.tornado_settings = {'headers':{
'Content-Security-Policy': "default-src 'self';frame-ancestors 'self'",
'X-Content-Type-Options':"nosniff",
'X-XSS-Protection':"1; mode=block",
}}

記事情報

  • 投稿日:2020年6月25日
  • 最終更新日:2020年6月28日

ARC050B 花束

この記事で使うアルゴリズム

二分探索

はじめに

カテゴリーAtCoder版蟻本中級編では、AtCoder 版!蟻本 (中級編)でまとめられている問題をPythonで解いています。

問題

https://atcoder.jp/contests/arc050/tasks/arc050_b

方針

二分探索を用いて解くことができます。

ABC023D 射撃王でも紹介させていただいたmeguru_bisectを使うと、二分探索をバグりにくく実装できます。

コード

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
R, B = map(int,input().split())
x, y = map(int,input().split())
def is_ok(K):
if K>R or K>B:
return False
if (R-K)//(x-1) + (B-K)//(y-1) >= K:
return True
return False

def meguru_bisect(ng, ok):
while (abs(ok - ng) > 1):
mid = (ok + ng) // 2
if is_ok(mid):
ok = mid
else:
ng = mid
return ok
print (meguru_bisect(10**19,0))

記事情報

  • 投稿日:2020年6月24日
  • 最終更新日:2020年6月24日