golangでCLIをしっかり作ろう

Topic

CLIを設計できるようになろうの一回目

Summary

以下のレポート記事を読んで、実際に同じものを作ってみる。

GopherCon 2019 - Design Command-Line Tools People Love

YouTube Designing Command-Lile Tool People Love

GopherCon 2019: Carolyn Van Slyck - Design Command-Line Tools People Love

覚えやすいかつメンテしやすいCLIを作る

今回作るもの

carolynvs/emote

  • an awesome CLI with emoticons (the pre-cursor of emojis)

Design Goals

  • Predictable → 予測できる、直感的
  • Task Oriented
  • Friendly to both and scripts
  • High quality

今回CLI作成で使うパッケージ。上三つは作者が同じ

How's day been?

Good 😉

LeetCode 101.Symmetric Tree

LeetCode 101.Symmetric Tree

leetcode.com

自分のアプローチ

  • 2つのサブノードを比較していく
  • 以下の条件を満たす場合は、symmetric と判定
    1. サブノードの root の値が等しい
    2. 左のサブノードの左の子ノードと右のサブノードの右の子ノード (外外)
    3. 右のサブノードの右の子ノードと右のサブノードの左の子ノード (内内)

自分のアプローチと解答例の差異

  • まず解答例では base case でサブツリーの root で比較している。
  • サブツリーの子ノードで判定すると 16 通りになりそれだけでも混乱する原因になる。
  • 起点となるhelper関数の引数の渡し方も解答例ではサブツリーのrootをそれぞれ渡しており、自分のアプローチではhelper関数を呼ぶ時点で条件分岐して煩雑になっている。
  • 解答例のように、ただツリーのrootを重複する形で渡してもうまくいく

解答例のアプローチ

  • base case は次の条件(1. || 2.)

    1. 両方とも null なら symmetric
    2. どちらかひとつ null なら asymmetric
    3. 両方とも null でなければ recursive case へ
  • recursive case では自分のアプローチと同じ条件を再帰的に課している(1.&& 2. && 3.)

    1. サブノードの root の値が等しい
    2. 左のサブノードの左の子ノードと右のサブノードの右の子ノード (外外)
    3. 右のサブノードの右の子ノードと右のサブノードの左の子ノード (内々)

f:id:mizushou:20200627142248p:plain
symmetricな構造

f:id:mizushou:20200627142355p:plain
asymmetricな構造

どうしたら解けたか

  • 実際にsymmetricとasymmetricの構造(深さ固定)を紙に数パターン書きだすと解答例のようなアプローチが見えてきたかも
  • ツリーのとノードのを分けてパターンを探したほうがよかった

解答例

public boolean isSymmetric(TreeNode root) {
  return isSymmetricHelper(root, root);
}

private boolean isSymmetricHelper(TreeNode lRoot, TreeNode rRoot) {
   if (lRoot == null && rRoot == null) return true;    //symmetricな構造
   if (lRoot == null || rRoot == null) return false;   //asymmetricな構造
   return (lRoot.val == rRoot.val)
       && isSymmetricHelper(lRoot.right, rRoot.left)
       && isSymmetricHelper(rRoot.left, lRoot.right);
}

自分の解法 (受かっていない)

public boolean isSymmetric(TreeNode root) {

    if (root == null) return true;
    if (root.left == null && root.right == null) return true;
    if (root.left != null && root.right != null) return isSymmetricHelper(root.left,
 root.right);
    return false;
  }

  private boolean isSymmetricHelper(TreeNode lRoot, TreeNode rRoot) {
    // base case
    if (lRoot.left == null && lRoot.right == null && rRoot.left == null && rRoot.right == null)
    {
      return lRoot.val == rRoot.val;
    }

    // recursive case
    if (lRoot.val == rRoot.val) {

      if ((lRoot.left == null && rRoot.left == null && lRoot.right == null && rRoot.right == null))
        return false;

      return isSymmetricHelper(lRoot.left, rRoot.right)
          && isSymmetricHelper(lRoot.right, rRoot.left);

    } else {
      return false;
    }
  }

Docker MySQLコンテナとWorkbenchでデータ設計環境を構築する

やりたいこと

  • WorkbenchのGUIで構築、でもローカルのDBを使いたくない
  • MySQLコンテナのDBでデータ設計
  • MySQLコンテナのデータを永続化
  • MySQLコンテナのMySQLのクエリログを残したい
  • 設計が終わったらWorkbenchでER図を出力

Github

github.com

作業

0 ローカルのMySQLを停止

  • Ubuntu機はMySQL自動起動しているので3306が使用されている。そのためMySQLコンテナ起動時にconflictするので停止する。
  • Workbenchが起動時に自動でローカルの3306と接続するので、3306を使いたい。
  • 以下にあるようにUbuntu16以上は systemctl または service コマンドを利用する。

Ubuntu 16 or higher

  • ちなみに service コマンドはラッパーのようなもので、高レベルコマンド。異なるLinux system間での共通インタフェース。 systemctl は実際のサービスをmanageする実体となるスクリプト

serverfault.com

service is an "high-level" command used for starting and stopping services in different unixes and linuxes. Depending on the "lower-level" service manager, service redirects on different binaries. For example, on CentOS 7 it redirects to systemctl, while on CentOS 6 it directly calls the relative /etc/init.d script. On the other hand, in older Ubuntu releases it redirects to upstart service is adequate for basic service management, while directly calling systemctl give greater control options.

  • systemctl コマンドに慣れてない。うろ覚え過ぎて sysctlと勘違いしてた。カーネルパラメータいじるコマンドと似た名前にするのやめて

dev.mysql.com

0-1 systemctlコマンド

  • systemctlがtabですぐに出せないから嫌い
  • サービス名が myslqd では起動できず、mysql.service。サービス名設定?みたいのあるのかもだけど本題でないのでそのまま
systemctl start mysql.service

systemctl status mysql.service
● mysql.service - MySQL Community Server
   Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: enabled)
   Active: active (running) since 月 2019-09-23 11:55:48 PDT; 20s ago

0-2 serviceコマンド

  • サービス名が mysqld じゃなく mysql
service mysql start

service mysql status
● mysql.service - MySQL Community Server
   Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: enabled)
   Active: active (running) since 月 2019-09-23 11:51:07 PDT; 2s ago

0-3 実際に停止

  • ローカルMySQL停止
systemctl stop mysql.service

● mysql.service - MySQL Community Server
   Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: enabled)
   Active: inactive (dead) since 月 2019-09-23 12:00:06 PDT; 7s ago

1 データの永続化

Containers are ephemeral in nature. They have a filesystem of their own. When containers die, the data stored locally in their filesystem is also gone.

www.ethernetresearch.com

  • ↑の記事には方法が2つとあるが、楽な共有ディレクトリを作るMethod2で永続化する

1-1 マウントするディレクトリ作成

ホスト側に共有ディレクトリ用のディレクトリを作成

mkdir mysql-data-dir

1-2 共有ディレクトリを指定して起動

起動。ホストから共有ディレクトリを確認、たしかにMySQL関連のファイルがあるのがわかる。

docker run -d --name mysql-server \
-e MYSQL_ROOT_PASSWORD=password \
-v ${path}/mysql-data-dir:/var/lib/mysql \
mysql:5.7.21
docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
1113f9beb233        mysql:5.7.21        "docker-entrypoint.s…"   2 minutes ago       Up 2 minutes        3306/tcp            mysql-server
ll mysql-data-dir
合計 185M
drwxr-x--- 2 guest-br046x guest-br046x 4.0K  9月 23 18:31 mysql
drwxr-x--- 2 guest-br046x guest-br046x 4.0K  9月 23 18:31 performance_schema
drwxr-x--- 2 guest-br046x guest-br046x  12K  9月 23 18:31 sys
-rw-r----- 1 guest-br046x guest-br046x   56  9月 23 18:31 auto.cnf
-rw------- 1 guest-br046x guest-br046x 1.7K  9月 23 18:31 ca-key.pem
-rw-r--r-- 1 guest-br046x guest-br046x 1.1K  9月 23 18:31 ca.pem
-rw-r--r-- 1 guest-br046x guest-br046x 1.1K  9月 23 18:31 client-cert.pem
-rw------- 1 guest-br046x guest-br046x 1.7K  9月 23 18:31 client-key.pem
-rw-r----- 1 guest-br046x guest-br046x 1.4K  9月 23 18:31 ib_buffer_pool
-rw-r----- 1 guest-br046x guest-br046x  48M  9月 23 18:31 ib_logfile0
-rw-r----- 1 guest-br046x guest-br046x  48M  9月 23 18:30 ib_logfile1
-rw-r----- 1 guest-br046x guest-br046x  76M  9月 23 18:31 ibdata1
-rw-r----- 1 guest-br046x guest-br046x  12M  9月 23 18:31 ibtmp1
-rw------- 1 guest-br046x guest-br046x 1.7K  9月 23 18:31 private_key.pem
-rw-r--r-- 1 guest-br046x guest-br046x  451  9月 23 18:31 public_key.pem
-rw-r--r-- 1 guest-br046x guest-br046x 1.1K  9月 23 18:31 server-cert.pem
-rw------- 1 guest-br046x guest-br046x 1.7K  9月 23 18:31 server-key.pem

2 port forwarding

  • ローカルの 3306MySQLコンテナの 3306 へport forwardingする
docker run -d -p 3306:3306 --name mysql-server -e MYSQL_ROOT_PASSWORD=password mysql:5.7.21
docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
09639fd616ea        mysql:5.7.21        "docker-entrypoint.s…"   6 seconds ago       Up 3 seconds        0.0.0.0:3306->3306/tcp   mysql-server

3 MySQLコンテナのログ設定

3-1 MySQLコンテナで必要なコマンドをインストールする

  • minminimalインストールなので、まず必要なコマンドをインストールする
  • ちなみに ps コマンドのインストールむずかった
docker exec -it mysql-server bash
apt-get update
apt-get install vim

stackoverflow.com

apt-get install procps

3-2 mysqldが参照しているmy.cnfを確認する

  • 以下の順番でmy.cnfを読み込んでいく
  • /etc/my.cnf が思い出しやすいので、 /etc/my.cnf を作成する

/etc/my.cnf Global options

SYSCONFDIR/my.cnf Global options

$MYSQL_HOME/my.cnf Server-specific options

defaults-extra-file The file specified with --defaults-extra-file=path, if any

~/.my.cnf User-specific options (in your home directory)

dba.stackexchange.com

# find / -name my.cnf
find: '/proc/1/map_files': Permission denied
/var/lib/dpkg/alternatives/my.cnf
/etc/alternatives/my.cnf
/etc/mysql/my.cnf

3-3 /etc/my.cnfを作成しログの設定を行う

  • my.cnfを編集して再起動するとコンテナ停止し、その後起動できない
  • 結局、docker-compose.ymlを用意してホストと共有することに
touch /etc/my.cnf
vim /etc/my.cnf

以下の内容を追記

[mysqld]
log = /var/log/mysql/query.log

4 docker-compose.ymlでまとめる

  • 結局、my.cnfロードできないのでdocker-compose.ymlを作ることに変更
  • 1から3までの内容をdocker-composeに集約する

4-1 ホスト側の準備

  • cnfファイルを用意する
    • 全クエリログ出力を有効、ログファイルのパス指定
    • デフォルトのerror.logのパスもクエリログと同じにしておく
[mysqld]

log-error   = /var/log/mysql/error.log

general_log=ON
general_log_file = /var/log/mysql/log_output.log

4-2 docker-compose.ymlを作成

  • コンテナのlogディレクトリをマウントするのに手こずった。permissionの問題でvolumesだけでは参照できない。
  • 下記の記事にあるとおり、単純にowner変更

stackoverflow.com

version: '3'
services:
  db:
    container_name: db_pg
    image: mysql:5.7.21
    environment:
      - "MYSQL_ROOT_PASSWORD=password"
      - "MYSQL_DATABASE=pg_db"
    ports:
      - "3306:3306"
    volumes:
      - db_pg_data:/var/lib/mysql
      - ./test.cnf:/etc/mysql/mysql.conf.d/test.cnf
      - ./logs:/var/log/mysql
    entrypoint: ""
    command: bash -c "chown -R mysql:mysql /var/log/mysql && exec /entrypoint.sh mysqld"

volumes:
    db_pg_data:

5. MySQLコンテナ起動

docker-compose up

使い方

1 クエリログをターミナルでtailしておく

sudo tailf log_output.log

2 Workbenchを起動

mysql-workbench

3 Workbenchでデータモデリングしていく

  • Workbenchの横にターミナルのログを開きつつ作業していく。Workbenchだけでもいいんだけど
  • Workbenchについては以下のエントリを参照

mizushou.hatenablog.com

英作文 NG集

目的

日常の英作文でのNG例やルールをメモしていく。あくまでも指摘された際の個人的なメモで、grammar的に正しいかまたはEnglish writing的に正しいのかはあまり確認をしない。ひとまずメモる記事。

grammar, English writingに基づいたルールは別記事で管理する。

一般

直接的な表現を使う(回りくどい言い回しをなるべく使わない)

例: not include -> without

# NG
If I select not include the meals, how much is the rent fee?

# OK
If I select without the meals, how much is the rent fee?

接続詞のsoの大文字、小文字

  • 別にこれはsoに限ったことではなく中学生レベルのルールだが、soが接続詞ってことを意識しないでパパっと書いてたらミスった
  • 主節にカンマで接続詞節繋ぐとき、接続詞を大文字にはしないよな、、、
    • 〜〜〜, When I'm student 〜〜とはしないよな
# NG
I'm interested in the your house, So I'd like to ask you some more questions.

# OK 
# soは結論?の接続詞
I'm interested in the your house, so I'd like to ask you some more questions.

メール

Nice to meet youは文面では使わない

文面でこれを書くやつはいないと言われた草

# NG
Hi, my name is Ash. Nice to meet you.

Python3 cheat sheet

  • 以下の記事を参考に、自分用のcheat sheetを作成していく

Pythonでこんなことできちゃうんです - Qiitaqiita.com

list, tuple, dictionary

comprehension

いわゆるリスト内記法

list, dictionary comprehensionのサンプル

swap

tuple使えばワンラインでswapできるよという小ネタ

小ネタサンプル

www.pythontutor.com

machine learning関連

activation function

NNで頻繁に使われるactivation function集。実際にスクラッチでモデルを実装をすることは少ないと思うけど一応。

  • LeRU(rectified linear)

NNで使うactivation functionのサンプル

6.86x Machine Learning with Python-From Linear Models to Deep Learning チェックリスト

Unit2 Nonlinear Classification, Linear regression, Collaborative Filtering

Project 2: Digit recognition (Part 1)

プロジェクトの概要

  • digit recognition problem using the MNIST (Mixed National Institute of Standards and Technology) database
  • 手書きの数字(0-9)画像の識別
  • 複数の手法を試してみる。そして、その結果を比較する。

MNISTのデータについて

  • binary images of handwritten digits
  • この手書きの数字画像はアメリ国勢調査局と高校生から収集されたデータ
    • The digits were collected from among Census Bureau employees and high school students.
  • training: 60,000
  • testing: 10,000
  • 28 * 28 pixels (784-dim)

問題

1. Introduction
2. Linear Regression with Closed Form Solution
3. Support Vector Machine
  • One vs. Rest SVM
  • Binary classification error
  • Implement C-SVM
    • C parameter in python’s sklearn library refers the regularization parameter
  • Multiclass SVM
4. Multinomial (Softmax) Regression and Gradient Descent
5. Temperature
6. Changing Labels
7. Classification Using Manually Crafted Features
8. Dimensionality Reduction Using PCA
9. Cubic Features
10. Kernel Methods

Unit3 Neural netowrk

Homework4

1. Neural Networks

  • Feed Forward Step

  • Decision Boundaries

  • Inverse Temperature

2. LSTM

  • LSTM states

  • LSTM states 2

  • LSTM info

3. Backpropagation

  • Computing the Error

  • Parameter Derivatives

  • Activation Functions: Sigmoid

  • Simple Network

    • chain ruleを適用する単純作業で凡ミス
  • SGD

参考

www.andreykurenkov.com

Backpropagation is one of those ideas like Bayes Rule that's "whoa, why didn't I think of that"...after you see it. It's just the plain old ordinary chain rule we learned early in calculus. Unfortunately, it's not as obvious or trivial as Bayes Rule (a one-line "proof" from the definition of conditional probability), and that Caused Problems... See, waaay back in 1969, when the idea of neural networks was just starting, some people pointed out that unless you have multiple layers, you can't solve problems that, well, aren't linearly separable. But with multiple layers, how can you ever figure out what the weights should be, hmm? HMMM? Pfft! Not possible, some people said. Ok, "some people" are Marvin MInsky and Seymour Papert. In 1969, they wrote a book called Perceptrons. I was in high school at the time, and had a habit of prowling the science section our our local library for new books, so I snagged Perceptrons when it first arrived. By about chapter 3, I was thinking..."They don't like this." I closed the book, and took it back. Apparently Minsky also went 'round telling his highly-placed contacts that neural networks were a dead end, and neural network research shouldn't be funded. (Yes yes, they were probably reacting to the AI hype and over-promising that led to the AI Winter...but they failed to recognize the difference between the intractable search-based methods of traditional AI...and the not-yet-named statistics-based methods of machine learning, of which neural networks were an early example.) And that killed the field for almost 20 years. But...even before that, assorted folks were busy solving the problem. Folks were working on pieces of it in the early 1960s. Paul Werbos dissertation detailing and analyzing backpropagation was published in 1974. These folks were available for Minsky and Papert to talk to... It wasn't until the re-re-discovery of backpropagation by Rumelhart, Hinton, Williams, and McClelland in 1986 that neural networks began the journey to acceptance all over again. The moral of the story is, if you have a Big Name, and lots of Clout, the more cautious you need to be about pooh-pooh-ing something. (I only found out recently about Minsky telling folks not to fund NN work, so I'm upset with them all over again.)

4. Word Embeddings

  • Word Embeddings
    • 正解だったけど勘。復習必要

Project 3: Digit recognition (Part 2)

プロジェクトの概要

  • digit recognition problem using the MNIST (Mixed National Institute of Standards and Technology) database
  • 手書きの数字(0-9)画像の識別
  • Part2では、neural netowrkでMINSTのデータを識別する
  • 2.-6.はsimpleなneural netsをスクラッチで実装する
  • 7.-10.は前半でスクラッチで行ったMINSTデータ識別をPyTorchを用いたdeep neural networkモデルで行ってみる

    Using a framework like PyTorch means you don't have to implement all of the details (like in the earlier problem) and can spend more time thinking through your high level architecture.

問題

1. Introduction
2. Neural Network Basics
  • 6.まではsimpleなneural netをスクラッチで実装していく

    You will implement the net from scratch (you will probably never do this again, don't worry

  • 今回のモデル
    • three layers
      1. Input layer
        • neuron * 2
      2. Hidden layer
        • neuron * 3
      3. Output layer
        • neuron * 1
3. Activation Functions
4. Training the Network
  • NNでデータをtrainするメソッドを実装する
  • Forward propagationを実装する。これはカンタン
  • 次にBack propagationをchain ruleで手計算してから実装する。これが一番辛かった
  • Back propagationで各パラメーター(重み)とバイアスをSGDで最適化する
  • numpy.vectorize()で関数をvectoriztion
5. Predicting the Test Data
  • 5.で実装したメソッドでtraining。最適化されたパラメータでoutputを計算
    • NeuralNetworkクラスのattributeにtraining後のパラメータがセットされているので、これを使ってoutputを計算するだけ。このoutputがpredictionになる
6. Conceptual Questions
7. Classification for MNIST using deep neural networks
  • 2.-6.ではスクラッチでsimpleなNNを組んでやったことを、今度はPytorchでdeep neural networkモデルでやってみる。
8. Fully-Connected Neural Networks
  • まずは用意されたコードを実行
  • mini grid searchでhyper parameterのチューニング。精度の比較
    • batch size
    • learning rate
    • momentum
    • activation function ReLU -> LeakyReLU
    • hidden layer size (neuronの数)
9. Convolutional Neural Networks
  • PyTorchでCNNを実装する
  • 構成
    • A convolutional layer with 32 filters of size 3×3
    • A ReLU nonlinearity
    • A max pooling layer with size 2×2
    • A convolutional layer with 64 filters of size 3×3
    • A ReLU nonlinearity
    • A max pooling layer with size 2×2
    • A flatten layer
    • A fully connected layer with 128 neurons
    • A dropout layer with drop probability 0.5
    • A fully-connected layer with 10 neurons
  • dropout layerが出てくる。透過率?を設定してチャネルを絞るイメージ。今回はp=0.5なのでチャネルが半分になる
  • dropout

  • Without GPU acceleration, you will likely find that this network takes quite a long time to train. For that reason, we don't expect you to actually train this network until convergence. Implementing the layers and verifying that you get approximately 93% training accuracy and 98% validation accuracy after one training epoch (this should take less than 10 minutes) is enough for this project. If you are curious, you can let the model train longer; if implemented correctly, your model should achieve >99% test accuracy after 10 epochs of training. If you have access to a CUDA compatible GPU, you could even try configuring PyTorch to use your GPU.

10. Overlapping, multi-digit MNIST
  • 時間切れでできなかった。あとでやる。

参考

If you're planning on trying to avoid use of np.vectorize (or the PyTorch equivalent), you may need to have different code in your ReLU functions for ndarray (or tensor, or list). Here's how to test what data type your function got passed: isinstance(x, t), where x is the input and t is a type specifier. isinstance() returns True or False, so can be used in an if statement. Here are the various type specifiers:

# Numpy ndarray
if isinstance(x, np.ndarray):
    # Nice vectorized code for Numpy arrays here.
# PyTorch tensor
# We may not have PyTorch imported, so try to import it here.
try:
    import torch
    if isinstance(x, torch.Tensor):
        # Appropriate code for PyTorch tensors here.
except:
    # No PyTorch available, so the input can't have been a PyTorch tensor.
    pass
# Python list (unlikely we'll get this, but still...)
if isinstance(x, list):
    # Your list code here.

Finish up with code for ordinary scalars.

As is pointed out in another thread, the grader for rectified_linear_unit_derivative is requiring that we return ints, even though it is passing us floats. If you find you want to distinguish between scalar int and float types, you can use "int" and "float" as type specifiers. (Python 3 doesn't have a distinction between "float" and "long", so you don't have to test for "long".) But since the grader wants only ints just now, this is moot.

# Python float
if isinstance(x, float):
    # Return floats if given floats...or not, because the grader wants ints.
# Python int
if isinstance(x, int):
    # Return ints if given ints...

Dockerコンテナ上のMySQL DBのER図をWorkbenchで自動作成する

内容

  • MySQL WorkbenchでローカルのMySQL DBのER図を自動作成してみる
  • ローカルのDBはDockerのMySQLコンテナ上のMySQL DB
  • 参考記事の手順を試してみて、上手くいくことを確認しただけの内容

前提

  • Ubuntu16.04
  • MySQLのDocker公式イメージで起動したMySQLコンテナ上のDBを使用
  • ホストの3306ポートをMySQLコンテナの3306にポートフォワーディングしている

参考

medium.com

www.linode.com

stackoverflow.com

ホストからMySQLコンテナのDBに接続できるか確認

  • 以下の様に-hでローカルを指定すれば接続できる
    • コンテナ起動直後はエラー出るかも
mysql -h127.0.0.1 -uroot -p

MySQL Workbenchをインストール

1. repository update, package upgrade

sudo apt update
sudo apt upgrade

2. install MySQL Workbench

sudo apt install mysql-workbench

3. run MySLQ Workbench

  • MySQLコンテナを立ち上げている状態(ホストの3306でポートフォワーディングしてる)で、Workbenchを起動するとMySQLコンテナのDBへのconnectionが表示されていた。
mysql-workbench

Create ER diagram

  • あとは以下の参考記事の通りにER図を作成する
  • 記事の手順どおりでER図を作成できた。作成したER図は画像ファイルやPDFでexportできるのでまぁまぁ便利

medium.com