SKYROCKETING WORK!

日常のエントロピーを上げてくぞ🚀

Linuxbrew - sudoを使えないLinuxのユーザがPackageを管理するための魔法の杖

拝啓 Linxubrew様、私はあなたに命そのものである時間を助けられました。
ここに感謝の手紙を記します...。

docs.brew.sh


という冗談はさておき、Linuxbrewというパッケージ管理ツールを紹介する。

LinuxbrewとはMac OS Xでは有名なパッケージ管理ツールであるHomebrewのLinux版という位置づけのものである。

しかし、考えてほしい。
Linuxの各ディストリビューションには、デフォルトで著名なaptやyumなどのパッケージ管理ツールが入っている。
そのため、このパッケージ管理ツールはいったいどこで使うのだろうか...?と思ったりしていた。

なんと、使い所は意外なところにあったのだ。

LinuxbrewのWebサイトのキャッチコピーを引用する。

It can be installed in your home directory, in which case it does not use sudo.

おわかりいただけただろうか。
Linuxbrewはsudoを使わずに、ホームディレクトリにインストールをすることができる。

セキュリティ上の理由などで学校や会社で使えるユーザにroot権限が与えられていないというのはよく聞く話である。
それゆえに、「apt-get sudo なし」やら"How to install packages in CentOS without root user?"。で検索し、あまりの面倒さに環境構築で途方に暮れるなんて経験はしたことがないだろうか。

Linuxbrewは、この問題を解決する魔法の杖である。
sudoが使えないユーザであっても、パッケージ管理をすることができる。
コマンドひとつでパッケージをインストールをすることができるようになるのだ。

インストール方法はWebサイト内にも書いてあるが、こちらにも日本語の解説とともに記しておく。

## install用スクリプト、sudoが使えなければ諸々のファイルなど~/.linuxbrew下にインストールされる
sh -c "$(curl -fsSL https://raw.githubusercontent.com/Linuxbrew/install/master/install.sh)"

## ここからはsudoが使えない前提で書いておく

## brewが吐き出す環境変数を読み込む
test -d ~/.linuxbrew && eval $(~/.linuxbrew/bin/brew shellenv)

## 環境変数を読み込むコマンドを.bash_profile (.profile) に書き加えておく
# CentOS/Fedora/RedHat
test -r ~/.bash_profile && echo "eval \$($(brew --prefix)/bin/brew shellenv)" >>~/.bash_profile

# Debian/Ubuntu 
echo "eval \$($(brew --prefix)/bin/brew shellenv)" >>~/.profile

以上の手順を踏むと、brewコマンドが使えるようになっているはずである。

brewとそのまま打ち込んで実行すると、以下のような基本的な使い方が出てくる。

Example usage:
  brew search [TEXT|/REGEX/]
  brew info [FORMULA...]
  brew install FORMULA...
  brew update
  brew upgrade [FORMULA...]
  brew uninstall FORMULA...
  brew list [FORMULA...]

Troubleshooting:
  brew config
  brew doctor
  brew install --verbose --debug FORMULA

Contributing:
  brew create [URL [--no-fetch]]
  brew edit [FORMULA...]

Further help:
  brew commands
  brew help [COMMAND]
  man brew
  https://docs.brew.sh

Linuxbrewを使えば、sudo利用できずとも快適なパッケージ管理ライフを楽しめるようになることだろう、きっと。

"Canonicalizing Open Knowledge Base"とはなにか、そしてその可能性。

この記事は自然言語処理アドベントカレンダー 2019その2)の18日目の記事です。
昨日はid:sh111hさんの10年前 (2009年) のACL論文を紹介する - エイエイレトリックでした。

はじめに

Canonicalzing Open Knowledge Basesというタスクをご存知でしょうか。
本記事ではいくつかの論文を例にざっとこのタスクを紹介していきます。

Canonicalizing Open Knowledge Basesってなに?

Galárraga et al.の"Canonicalizing Open Knowledge Bases"に端を発する、Open Knowledge BaseのEntityとRelationを正規化(canonicalizing)していくタスクです。*1
(Entityは固有名詞などの何かを表現した名詞で、Relationはis-aやhas-aのようなEntity同士の関係を表現したものです。)

そもそもOpen Knowledge Baseってなに?

Open Knowledge BaseはOpen Information Extraction(以下、OpenIE)によって出力されたTripleからなるKnowledge Base(以下、KBと略)のことです。

入力された文書から(主語フレーズ, 述語フレーズ, 目的語フレーズ)という形式のTripleをTupleとして抽出して、それを(Entity, Relation, Entity)として捉えてEntity間のRelationを得るタスクです。

そして、OpenIEの抽出結果であるTripleはKBのように捉えることができ、これをOpenKBと呼んでいます。

OpenIEについて詳しく知りたいという方は次のブログエントリや論文がとてもわかりやすいので見ていただければと適宜参照していただければ...!

Knowledge Baseって...?

Knowledge base - Wikipediaから引用させていただくと...

Knowledge Baseはコンピュータシステムによって利用される複雑な構造化、あるいは非構造化された情報を記憶する技術。

とのこと。

つまり、Entity同士をRelationで結んで知識でネットワークを作れるように記録し、これをコンピュータから扱えるようにしているものです。

代表例としては、DBPediaWikidataFreeBaseYAGOなどのプロダクトがあり、これらはOntological KBと呼ばれています。

Open KBの可能性と問題

Open KBはOntological KBとどう違うのでしょうか。

Entity同士をRelationで結んで知識のネットワーク構造を作るというKBとしての機能は同じです。
しかし、OpenKBは成り立ちが根本的に異なるため、Ontological KBに比べて変化に強く柔軟であるという強みを持っています。

Ontological KBの多くがコミュニティや団体によって、Wikipediaなどのソースを元に更新していくことで作られています。
なので、アプリケーションで利用中のKBが新しい情報を取り入れるためには、以下のようなプロセスを経る必要があります。

  1. ソース元の更新
  2. コミュニティによる配布
  3. 配布されたKBの導入

一方で、OpenKBはOpenIEに文書を入力することで得られる出力であるTripleから構成されます。
つまり、OpenKBは保有している文書が更新されていていれば、OpenIEを実行するだけで新しい情報を取り入れることができるのです。

この側面だけ見ると、OpenKBが夢のような手法のように見えてきますが、もちろん課題もあります。
深刻な課題の一つとして挙げられるのは、OpenIEによって得られるTripleが含んでいるEntityやRelationを表層の形のままで抽出してしまっているということです。

それによって、同じ意味を持つ語や節にも関わらず、別のEntityやRelationに認識されてしまうという課題が引き起こされます。

例えば、CESIが論文内で挙げている例をみてみましょう。
同じドキュメント内に以下の二つの文章があるとします。

  • Barack Obama was the president of US.
  • Obama was born in Honolulu.

これらが含まれたドキュメントをOpenIEに入力すると、下記のようなTripleを出力します。

  • (Barack Obama, was president of, US)
  • (Obama, born in, Honolulu)

このとき、文中ではBarack ObamaObamaは同じ人物を示しているはずですが、OpenIEを介すると別のEntityとして出力されてしまっています。
そして、これと同様の課題がRelationでも発生しえます。

こうした課題がOpenKBを実際の運用で利用するのを難しくしています。

Canonicalizingとはなにか

さきほどOpenIEの出力結果を利用すると同じような意味のEntityとRelationがダブってしまう可能性があるというOpenKBの課題を取り上げました。
Canonicalizing Open Knowledge Baseとは、この課題を解決しようというものです。

このタスクにおけるCanonicalizingとは同様の意味を持つ複数の表現を1つにまとめることだと説明できます。

つまり、先程の例を利用するとBarack ObamaObamaという二つの名詞フレーズをどちらかの表現に寄せてしまうということです。
例えば、ObamaBarack Obamaとして扱うといった具合です。

このCanonicalizingをする手法としては、現在提案されて手法の中ではClusteringを利用する方法が多いようです。

Canonicalizing Open KBの流れと現在

代表的な先行研究としては三つの論文が存在しています。

Canonicalizing Open Knowledge Base

ACM CIKM 2014のGalárraga et al.による論文。
タスクとしてCanonicalizing Open Knowledge Baseをはじめて定義しました。

Clusteringによって、Entityの名詞フレーズとRelationの関係フレーズをCanonicalizeしていく、という手法です。 EntityのClusteringでは、階層的クラスタリングを用いていてクラスタリングのための使われる類似度のためにSimilarity Functionが定義されています。
そのSimilarity Functionとは、仮説から良い特徴量空間から距離関数を選び、それらをロジスティクス回帰を用いて結合したものです。

また、RelationのClusteringでは、Galárraga et al.によるAMIEと呼ばれる統計的に包摂関係を導き出す手法を適用しています。
AMIEの出力結果を元に共通の包摂関係になったフレーズを同じクラスターとして扱って、いくつかのルールに基づいて代表的な語を選ぶことでCanonicalizeします。

CESI: Canonicalizing Open Knowledge Bases using Embeddings and Side Information

The WebConf 2018 (WWW 2018)のVashishth et al.による論文。

f:id:otakumesi:20191216210139p:plain
https://github.com/malllabiisc/cesi より引用

CESIでは、Galárraga et al. の手法をover manually-defined feature spacesであると指摘していて、学習されたEmbeddingからClusteringをする手法を提案しています。

CESIの特徴はOpenIEのTripleを活用して各フレーズのSide Informationを取得し、それを利用して名詞フレーズと関係フレーズのEmbeddingを学習するところにあります。
そして、そのEmbeddingの空間における距離をもとにClusteringをしていくアーキテクチャになっています。

Embeddingの目的関数は、Nickel et al.のHolEというKnowledge GraphのEmbeddingのlossをベースにしたものを使っています。

また、Side InformationとはでOpenIEのTripleに含まれる有用なコンテキストを利用して得られる情報です。
これは名詞フレーズや関係フレーズそれぞれで別々のものが定義されています。

CESIには、提案手法のコードや提案データセットをまとめたリポジトリが存在しているので、もう少し詳しく知りたい方はこちらへ。
github.com

CaRe: Open Knowledge Graph Embeddings

EMNLP 2019のGupta et al.による論文。

f:id:otakumesi:20191216210305p:plain
https://github.com/malllabiisc/CaRe より引用

CaReは前者二つとは、少し毛色が違っています。

というのも...
前者二つはOpenKBを入力にして、OpenKBの精度を上げることに焦点を当てています。
一方で、CaReはOpenKB自身をCanonicalizeするのではなく、OpenKBから作るKnowledge GraphのCanonicalizeを目的としているからです。

そして、CaReの入力はOpenIEの実行結果ではなくCESIの出力結果であるCanonicalizeされたOpen Knowledge Baseです。
それゆえ、これはCanonicalizing Open Knowledge Baseを拡張するモデルだとも考えられます。

また、CaReではこのCanonicalizeされたOpen Knowledge Baseをaugmented OpenKGと表現しており、このaugmented OpenKGからKnowledge Graph Embeddingを学習していくのが特徴です。

Careでは、3つのコンポーネントから構成されるTriplet Lossを用いて学習されます。
コンポーネントはそれぞれ下記のとおりで...

  1. 主語フレーズをCanonicalizeするCanonical Cluster Encoder Network(CN)
  2. 述語フレーズをCanonicalizeするPhrase Encoder Network(PN)
  3. 目的語フレーズをCanonicalizeするCanonical Cluster Encoder Network(CN)

CNはLocal Averaging Networkと呼ばれるGraph Neural Networkのようなアーキテクチャを定義し、名詞フレーズをembeddingにEncodeしています。
一方で、PNではbidirectional GRUを用いて最後に両方向の隠れ層を結合することで、関係フレーズをEncodeしています。

CaReにも提案手法のコードのリポジトリが存在するため、もう少し詳しく調べてみたい方はこちらへ。
github.com

最後に

Vashishth et al.Gupta et al.も言及しているようにCanonicalizing Open Knowledge Baseは、まだまだ未開拓な分野です。

しかし、これらの技術が実際のアプリケーションで運用が可能になったとき、様々な利益をもたらすと考えていて大きな可能性を秘めた分野だとも感じています。
(例えば、Webアプリケーションの世界ではファセットナビゲーションの作成に応用ができそうに見えます。)
そのため、自分は注目していきたいなと考えていて、アドベントカレンダーとして書かせていだきました。

自分はNLPの研究者としてはまだまだ未熟なため、間違った記述を書いてしまっているかもしれません...。
「おや?」と思うことがあれば、よければご指摘ください。

参考文献


明日のアドベントカレンダーは、mhangyoさんのウェブリードコーパスについての記事と、yusa87さんのGiNZAに関する記事だそうです!

*1:Knowledge Baseではなく、Knowledge Graphが対象となったりするがそれほど変わらない。

変化が激しく脆いドメインで技術的負債を増やさない設計

はじめに

ソフトウェア設計についてのポエム。
それも、ドメインが短期的なサイクルで大きく変化をしてしまうような領域での。
僕が携わる領域、つまりメディアサイトでのSEO施策を反映するシステムでの経験を念頭にしている。

結論から言えば、ビルド・アンド・スクラップを可能にしようという話です。

「変化の激しく脆いドメイン」とは?

問題の解決策のコアとなる部分が頻繁に変わるドメインのこと。
特にプロダクトのライフサイクルよりも早く変わるドメインのことを指したい。

僕が携わっている「Webメディア」というのも、この変化の激しく脆いドメインに当たると思う。
Webメディアにおける開発では、SEOやUXについて考慮することは避けることはできない。
しかし、SEOやUXは頻繁に変わるGoogleのアルゴリズムやユーザの嗜好によって正解が変わっていく
一年前に正解だったものが、次の年にはただの技術的負債になっている可能性すらあるからだ。

補足: ドメイン is 何?

少なくとも僕が表す文脈で言えば「問題領域」と訳されるもの。
以下の記事で「problem domain」と表されているものを指している。

オブジェクト指向分析 (OOA; object-oriented analysis) は、システム化の対象となる領域 (問題領域; problem domain) を対象とし、分析の対象となる問題領域に存在するさまざまな情報の概念モデル (conceptual model) を作ることを目標とする工程である。
オブジェクト指向分析設計 - Wikipedia』より

ドメインや責務の賞味期限を考えて切り分ける

設計をするとき、私たちはドメインに横たわる概念を責務として表現している。 *1
「決済」というドメインの中には、「買い物の合計額を計算する」「クレジットカード会社との取引を仲介してくれるサービスへ通信をする」などといった責務があるという具合に。

そうしたドメインや責務には賞味期限がある。
賞味期限が異なるモノを一緒にしてしまうと、本来は賞味期限が長かったモノまで賞味期限が 短くなってしまう。

変わりやすさを基準に概念に境界を引いていく

環境や状況というのは常に変化をするもので、それにともなってある時に問題だったものが問題ではなくなり、その解決策も解決策ではなくなってしまう。
時間だけでなく場所を変えるだけでも、問題が変化してしまうことさえある。
ましてや、解決策が技術的負債となって襲いかかってるくることも...。

例えば、和暦だ。
和暦は日本ローカルな紀年法で世界では使われていない。
日本で展開しているサービスで生年月日を表現する際に、その表現の解決策として和暦を使っていたとする。
そのサービスが運良く成功して海外展開をしようという時、その概念に依存して構築されたシステムは技術的負債になるかもしれない。

このような変化によって発生する技術的負債に対処するためには、概念の変わりやすさを基準にして設計を考えるといい。
ここで「変わりやすさ」を基準に、変わりやすいものを脆い、変わりにくいものを堅いとする。
ある概念を表現しようとするとき、概念を掘り下げて境界を引き脆い責務と堅い責務を切り分けましょうという話。

そうすることで、堅い責務を表現したモジュールを脆い責務の変化の影響から守れる。*2
つまり、脆い責務によって発生するシステム改修の影響を最小限にとどめることができる。

先にあげた例で説明すると「和暦は時間の表現方法の一種類に過ぎないので、時間を表す責務と切り分けて考えると良い」という話。

時間を表す責務は堅く、時間の記法である和暦の責務は脆い概念にあたる。
特に和暦は天皇の交代という短めのサイクルで変化が起こることがわかる脆い概念なので。

コードに落として考えるとしたら、時間class時間表現classを別々にすると良い、という感じだろうか。
とはいえ、時間表現は様々なバリエーションがあるコト自体がわかりきっているため、interfaceabstract class、あるいはダックタイピングの利用を検討すべきだと思う。
時間表現interfaceでアプリケーション内における時間表現の概念を定義して、それを実装する和暦表現classで計算して出力するという具合だ。

脆い概念を堅い概念に依存させる

そして、切り分けた2つの責務を組み合わせて元の概念の表現しようとするときは、脆い責務を堅い責務に依存させたほうがいい。
コード上の変更の影響は結合によって発生していて、その影響は依存関係によって各モジュールへと伝播していくので。

これも具体的に説明する。

時間という概念を表す時間class時間表現の1つである和暦表現classがいるとしよう。

Rubyの擬似コードで表すならば、以下のように設計できる。

# 時間の記法を表現する責務である
time = 時間.now
# 時間classはその代表値として西暦を使っているとする
puts time.year.to_s
#=> "2019年"

j_time = 和暦表現.new(time)
# 西暦から和暦に変換して出力する
puts j_time.year.to_s
#=> "平成31年"

# Rubyならば以下のようなメソッドを生やして型変換っぽくメソッドを追加するのもあり...かも?
# 時間#to_ja
#
# class Time
#   ...
#   def to_ja
#     和暦表現.new(self)
#   end
# end

汎用的な時間表現を西暦の時間classにもたせて、和暦表現が必要なタイミングのみに変換をするように設計する。
こうすることで、和暦表現classに新しい年号を追加するというイベントが発生しても、変更の影響範囲は和暦表現classとその利用箇所にだけとどまる。
時間classを利用している箇所には、変更の影響が及ばないはずだ。

時間class自身も、便宜上の理由で西暦を使っていて、時間表現でないと言ったら嘘になる。
とはいえ、時間を表現するためには何かで時間を代表させる必要があり、そこで西暦を選んだのは国や時間が変わっても使われているだろうという見込みが高いからだ。
和暦に依存する場合に比べて変更が発生する回数少ない堅い設計になるはずだ。

賞味期限の早いものは「捨てやすく」しよう

賞味期限が切れたモジュールは、開発の邪魔になりがちである。
いわゆる技術的負債となっていることが多い。

  • 無意味だけれど、なぜか動き続けているロジック
  • 一部の機能はほしいけれど、そこまで大きい必要がない過剰に高機能なclass
  • メディア側では見えていないのになぜか残っているコード
  • grepにたくさん引っかかる謎の動いていないコード
  • ...etc

こうした技術的負債は、回り回っていつか自分の足を撃ち抜くような事故に至る可能性がある。
また、こうした技術的負債によって、プロダクトのコード量が無駄に増え、変更の影響範囲が拡大し開発工数を増やすこともある。
そして、その存在自体が割れ窓理論的にコードの治安も悪くしがちなため、早急にご退場を願ったほうがよい。
割れ窓理論 - Wikipedia

とはいえ、そうした技術的負債も過去では金脈だった可能性もあり、様々な施策で利用されて巨大なモジュールと化し、簡単には捨てられない可能性がある。

技術的負債を捨てやすい設計にするためには、不要になる確率の高いモジュール(以下、脆いモジュール)の依存関係を最小限に抑える設計をすることだ。

脆いモジュールとは、変化の激しい領域で設計されたものであることが多い。
それは上で説明したような脆い概念の領域だ。

例えば、社内システムで職場のルールを実装する場合がここに当たるだろうか。
おそらく、ある年に作られたルールが、次の年には撤回されている可能性すらあるはずだ。

そして、脆いモジュールの依存関係を最小限に抑えるとは、「依存性逆転の原則」に従うことである。
依存性逆転の原則 - Wikipedia

というのも具体的な概念ほど脆い傾向があるため。
なので、具体的な概念に依存する必要がある場合は、それが変化することを前提にするとよい。
つまり、具体を直接使うのではなく、その抽象に依存するように設計するということ。

総務に備品の購入の申請をする社内システムがあるとしよう。
入力フォームで必要事項を記入し申請ボタンを押すと、備品の購入ルールに基づいたチェックが走ると考えてほしい。

そこで、ルールチェックclassと、個々のルールを表現した申請ごとの上限額ルールclass金額の参照元の入力ルールclassなどがあると想像してほしい。
このときに、備品購入ルールチェッカーclassは直にそれらのルールclassを実行するのではなく、それらのルールの抽象を抜き出してをinterfaceabstract classあるいはダックタイピングとして定義をして、それに依存するということだ。

Rubyの擬似コードで表すならば、以下のように設計できるだろうか。

# すべてのルールclassは、
# 抽象を抜き出すと「フォームの内容が正しいかどうかを返すという責務を負っている」とし、
# その結果を#valid?で返すというダックタイプと考えた。

class 備品購入ルールチェッカー
  def initialize(form)
    # RULESは下記のルールclassを配列にしたモノ
    # ルールclassを配列で取得できれば定数だろうがYAMLだろうがJSONだろうがなんでも良い
    @rules = RULES.map { |rule| rule.new(form) }
  end

  def valid?
    # すべてのルールの`#valid?`がtrueであれば、trueを返す
    @rules.all?(&:valid?)
  end
end

class 申請ごとの上限額ルール
  ...
  def valid?
    # 申請内の上限額が超えていないかをチェックする
    ...
  end
end

class 金額の参照元の入力ルール
  ...
  def valid?
    # 金額の参照元が正しく入力されているかをチェックする
    ...
  end
end
...

こうすることで、ある年にルールが増えたり消えたりしても、ルールclassを追加したり削除をしたりするだけで済む。
ルールclassを利用する側である備品購入ルールチェッカーclassのロジックを変更する必要はない。*3

最後に

この僕の考えは以下の書籍がベースになっている。
非常にオススメなので、本屋などでお手にとっていただければと思う。

*1:「そもそも責務ってなんだよ」という方にオススメの記事。 オブジェクト指向設計帖 巻之二

*2:モジュールという表現は、各プログラミング言語におけるclassやpackageなどのひとかたまりのコードを表している。

*3:ルールclassの配列の取得に定数を利用している場合は定数を修正する必要はあるけれど

『単語埋め込み』について調べたのでまとめてみた

単語埋め込み(Word Embedding)について調べたのでメモを簡単にまとめる。

ここ最近の自分の興味が自然言語処理に向いていて、その基礎となる概念として調べる必要があった。

単語の分散表現とは

単語の分散表現とも言われる。

深層学習ベースの自然言語処理で単語を表現する手法。
語彙の特徴を表現するベクトル空間に、単語の特徴量を表すベクトルを埋め込むことで語彙を表現する。

単語埋め込みの簡易図
図1. 単語埋め込みの簡易図(字が汚い手書きで申し訳ない)

なにが嬉しいのか

単語同士のベクトルの距離を比較することで類似度関連性を計算できるようになる。
図1の例を利用すると...

  • 「ネコ」と「ペルシャネコ」は距離が近いため、類似度も高く関連性も高いと言えそうだ
  • 「ネコ」と「犬」は距離が遠いため、類似度は低めっぽいが「ぞうきん」に比べれば近いので関連性はありそう
  • 「ぞうきん」と「犬」「ネコ」は類似度も低いし関連性も低そう

分散表現はどうやって獲得するの?

言語モデルを通して学習することによって獲得できる。

代表的なモデル

  • ニューラル言語モデル
  • CBoWモデル
  • skip-gramモデル

特にCBoWやskip-gramは、word2vecで使われている。

そもそも「単語埋め込み」や「単語の分散表現」の由来ってなに?

「単語埋め込み」の由来

最初の説明に書いたものをそのままコピペするようだけれど...
語彙の特徴を表現するベクトル空間に、単語の特徴量を表すベクトルを埋め込むことで語彙を表現する。」ことが由来。

「単語の分散表現」の由来

以下の2つの概念が組み合わさって「単語の分散表現」という概念を構成している。

【ニューラルネットワーク方面からの由来】

そもそも「分散表現」という用語は、認知心理学とニューラルネットワークの研究が起源。
脳のモデル化をする際に事象や概念といった離散的なモノを特徴量のベクトルとして表現するために登場した。

【自然言語処理方面からの由来】

自然言語処理には、1950年代から「分布仮説」という考えがある。
これは「単語の意味はその単語が使われた周囲の文脈によって決まる」という仮説。 この仮説に基づいて得られたベクトル表現も「分散表現」とも呼ばれた。

【2つの概念が組み合わさる】

初期のニューラル言語モデルが分散仮説の考え方をそのまま利用している考えれるようなモデルだった。
そのため、ニューラルネットワークの分散表現を獲得するのに分布仮説を用いてると解釈でき、両者の考えが統合されていった。

最後に

間違ってることがあったら指摘してください、早急に修正します :dogeza:

参考文献

プログラミングに向いてないかと思ってたけどなんとかなっている話

note.mu

バズってる記事への便乗記事。

僕自身がもともと絶望的にプログラミングに向いていないと思っていた人間だったので語りたくなった。

【お話をする内容】

  • 現在の私のスペック
  • なぜプログラミングが向いていないと思ったのか
  • どのようにして書けるようになってきたのか

現在の私のスペック

  • 24歳で文系卒(隠すと良くないので補足すると高校の頃は情報学科的なところにいた)
  • 都内のWeb企業でWebエンジニアをしている
  • 普通にWebエンジニアとして仕事する分には特に支障がない程度には書ける(と思っている)

なぜプログラミングが向いていないと思ったのか

ひとことで言えば、まったく「書ける気がしなかった」からだ。
特にコードの意味がわからなかった。
プログラミング言語やフレームワークの教科書を開くと、サンプルコードが書いてあると思う。
それを見るたびに、「え、世のソフトウェアエンジニアはこれ全部を暗記してんの?無理じゃね?」とか思っていた。

ましてや、高校の頃に情報学科にいて3年間もプログラミングについて学んだにもかかわらず、いま思うとコピペプログラマくらいの力しかついていなかった。*1
他人のコードをコピペして動くまで勘で書き換えていくことくらいしかできなかったのだ。

どのようにして書けるようになってきたのか

僕にとっての転換点はいくつもある。
ざっくりまとめると以下の4つだ。

  • リーダブルコードに出会う
  • コーディングを支える技術に出会う
  • コードリーディングをするようになった
  • オブジェクト指向設計を勉強した

リーダブルコードに出会う

最初の転機は「リーダブルコード」に出会ったことだ。
この本は「プログラムは読めるモノ」だという認識を僕に与えてくれた。
それまでは記号の羅列にしか見えなかったコードが、この本との出会いを境に読めるものに変わった。

この本を読むまでは関数が「よくわからん記号で名付けられたブラックボックス」に見えていた。
しかし、関数は実は「つけられた名前のとおりに振る舞う道具」だったのだ。
これは、当時の僕には衝撃的で世界が変わるようだった。

この本をキッカケに知らない英単語が使われている関数名は、辞書で調べて意味を把握するようにしている。

また、私が書くコードにも「意図」が込められるようになった。
atestと名付けられていた変数名や関数名が、userfollow_userに変わったのだ。

コーディングを支える技術に出会う

リーダブルコードを読み終わってあとでも、いまいちよくわかっていない概念があった。
それは各種言語機能とライブラリの関数の違いだった。
classforputsraise StandardErrorの違いがわかっていなかったのだ。
それを解決してくれたのが「コーディングを支える技術」だった。

コーディングを支える技術 ~成り立ちから学ぶプログラミング作法 (WEB+DB PRESS plus)

コーディングを支える技術 ~成り立ちから学ぶプログラミング作法 (WEB+DB PRESS plus)

本書はある言語機能はどういったものでなにを解決するために現れたのかを解説している本だ。
この本もまた僕のプログラミングへの視点を変えてくれた。
それまでごった煮だった概念が各種の言語機能とその他で見分けが付くようになったのだ。

そして、この本はプログラミング言語の違いは言語機能の違いにあるという認識を与えてくれた。

コードリーディングをするようになった

大学2年生の春に、Webアプリ開発を学ぼうとRailsチュートリアルを3回ほど繰り返した。
チュートリアルを終え、意気揚々とアプリケーションを作り始めると数多くの壁にぶつかったことを覚えている。
チュートリアルで学んでないことができなかったからだ。

その結果として「XXXはどうやってやるのだろうか?」というヒントを得るべく、Railsで作られたOSSのソースコードを参考にするようになった。

これは非常に正解だった。
洗練されたOSSは、素晴らしいレシピブックだったからだ。
「どうすれば読めるコードになるのか」がそこにあるのだ。
見事な処理の分割の仕方を目の当たりにして、僕に「設計」の存在を意識させるキッカケとなった。

オブジェクト指向設計を勉強した

コードリーディングをするようになると、OSSを開発している人たちは「なぜ、こんなコードを思いつくのだろうか」と考えるようになった。

思いつき方がまったくわからない僕は「やはりプログラミングの才能がなかったのだ」と思い始めていた。
なんとかわかる方法がないかと一生懸命調べ続けた。
迷走して「プログラマ 思考法」とかで調べてた気がする。

そんなこんなである時に、たまたま「どうやら多くのクラスはデザインパターンというものを参考作られているらしい」ということがわかった。
そして、その概念がオブジェクト指向設計の延長にあることを知り、その勉強をしようと考えた。

以下の記事を読んで、「オブジェクト指向のこころ」を買った。*2

takatoshiono.hatenablog.com

オブジェクト指向のこころ (SOFTWARE PATTERNS SERIES)

オブジェクト指向のこころ (SOFTWARE PATTERNS SERIES)

  • 作者: アラン・シャロウェイ,ジェームズ・R・トロット,村上雅章
  • 出版社/メーカー: 丸善出版
  • 発売日: 2014/03/11
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログ (6件) を見る

この本ははじめて読むオブジェクト指向の本としては非常に難しくて、読み終えるのに1ヶ月半くらいかかった。
蛍光ペンをめちゃくちゃ引いて読み直したり、付箋を付けて解釈して自分の言葉に直したりを繰り返した覚えがある。

この本で学んだもっとも重要なモノは「責務」という概念だ。
オブジェクト指向設計とは「責務を分割したり組み合わせてデザインすることだ」という認識を得られた。
本書によって、僕の見る世界がまた変わったのだった。

そして、この本を読み終えたあとも、オブジェクト指向をいまいちよくわかってない部分も多く、補足をしてくれる本を探していた。
そんな矢先に以下の記事に出会って「オブジェクト指向実践ガイド」を購入した。*3
tango-ruby.hatenablog.com

(当時はまだ日本語版が出版されていなく、すがる思いで原著を買った。)

この本は徹頭徹尾「実践」に重きをおいた本で、非常にわかりやすい。
小さく粗く作って、綺麗で柔軟な強い設計に改善していく過程を追っていける。
そのため、「設計しながらコードを書く」方法を学べる。
これはまさに僕がわかっていなかった「コードの書き方」への明確なアンサーだった。

そして、この本で最も学んだことは「長く生きるアプリケーションは変更されていく」ことと、「変更に強い設計とはなにか」ということだった。

この本を読み終えたあたりでようやく意図してコードを書くことができるようになったと自覚できるようになったと思う。

まとめ

かくして、少しずつ視点の変化を積み重ねることで、Webエンジニアとしてなんとか働ける程度の技術力にはなったのである。

ちなみに「どのようにして書けるようになってきたのか」のすべてを達成するのに数年くらいかけている。
それくらいプログラミングは苦手だったのだが、プログラミングが好きだったこととできるようになることを楽しめたのが大きかった。
一歩前進するだけで、自分は実はプログラミングの才能があったんじゃないと錯覚するくらいには単純な人間だったため、ここまで勉強をし続けられたのだ。

「才能がなくて『プログラミング』を諦めよう」と考えている人も、時間さえ投資すれば最低限のプログラミングくらいはできるようになるんだよと思っていただけたら幸いである。

*1:末恐ろしいことに、この頃の僕も「プログラミングはできる」と思っていた。すぐにその幻想は崩れて才能がないとうなだれるのだが。

*2:当時は読めるような技術力がついたら記事を読もうとブクマしておく癖があったので、マイブックマークでオブジェクト指向と検索したら上の方に来たのだ

*3:ちょうど、Rubyで書かれていたのも買う理由になった。

hubを使ってターミナルからGitHubリポジトリを作ろう

GitHubにリポジトリを作るとき、多くの方がちょっと面倒な手続きを踏んでるんじゃないかと思います。
ブラウザを開いて、GitHubのWebページにアクセスをし、それからやっとリポジトリを作るという手続きをしているのかなと思います。
ちょっと面倒くさいですよね。
「Gitのブランチを切るのと同じ感覚で、CLIからコマンドを叩いて作れたら楽なのになぁ」とか思っていたのですが、なんと存在していました。

hubという名のCLIツールです。

hub

hubとは、GitHubが開発しているgitコマンドを拡張したコマンドです。

github.com

通常のgitのコマンドと同様の操作に加えていくつかの操作を追加しています。
以下はその一部の例。

hub create # GitHubにリモートリポジトリを作成する
hub delete # GitHubのリモートリポジトリを削除する
hub browse # 現在のリポジトリのGitHubページを開く
hub ci-status # CIの結果を出力する
hub compare  <ブランチ名> # masterと指定したブランチのdiffを確認する画面を出す
hub pr list # プルリクエストのリストを表示する
hub pr checkout <プルリクエストの番号> # プルリクエストのブランチをチェックアウトする
hub pull-request -h <ブランチ名> # ブランチ名に対してプルリクエストを作成する
hub release # リリース番号の一覧を表示する
hub sync # リモートリポジトリで削除されたブランチなどを消してくれたり、いろいろやってくれるっぽい

インストール方法

公式サイトに書いてあります。
以下は情報を転載したもの。

# Macの場合
brew install hub

# Windowsの場合
scoop install hub

# Linuxの場合は各種パッケージ管理ツールにて

使い方

基本的にはGitと同じです。
上記のGitHub系機能を利用すると、最初の1回目は以下のようなプロンプトが表示されます。

hub create
github.com username: <ユーザ名を入力>
github.com password for <ユーザ名> (never stored): <パスワードを入力>

以降はパスワードのみが要求されるようになります。
しかし、GITHUB_USERGITHUB_PASSWORDを環境変数に指定しておくと、それを利用するようになります。

GitHub Enterpriseなどでは、もう少し細かい設定が必要なようです。
hub(1) - make git easier with GitHub


hubを使って、ストレスのないGitHubライフを楽しんでいきたいですね。

Courseraの機械学習コースを働きながら2週間で修了した話

思い立ってCourseraの機械学習コースを修了した。

f:id:otakumesi:20181220161916p:plain
Coursera 機械学習コースの修了書

モチベーション

半年前から「いつかやろう」と思っていたが、モチベーションが高まらなかったため後回しになっていた。
しかし、ここ最近になって自然言語処理に興味を持って勉強を始めている。
そのため、機械学習を避けては通れなくなったのである。

そこで、意を決して評判の良いというCourseraの機械学習コースを受けたのだった。

機械学習コースの感想

「受けてよかった」という気持ちとAndrew先生へのリスペクトでいっぱいになっている。

「機械学習やりたいけどなんもわからん」という人が、いの一番に受けるべき講座だなと思った。
この講座を修了して、ようやく機械学習を学んでいくためのスタート地点に立てたなという感覚がある。
つまり、「機械学習なんもわからん」から「機械学習のちょっと難しそうな本くらいは読めそう」くらいにはなった(と思いたい)。

なんと言っても、Andrew先生の講義が非常に良い。
というのも、複雑な理論の説明の後には直感的理解の講義を挟んでフォローしてくれるのである。
抽象的な概念に面食らっても、次の動画に進めば理解できるような構成になっている。
なので、全く理解できなくて心配になったとしても次に進めばよい。
そういう構成なので安心して講義を進めていける。

また、機械学習という分野に対する鳥瞰図が得られることが一番の収穫だった。
僕は学習のはじめに鳥瞰図を得ることは学習において非常に大事している。
自分が本当にやりたいことに向かうためには、これからどの方向に進んでいけばいいのかがわかるようになるからだ。

この講義は、今後の僕の学習計画に道筋を与えてくれた。
なので、Andrew先生に感謝の気持ちでいっぱいである。

機械学習コースで学べること

  • 機械学習に必要な基礎的な数学
  • 基礎的な機械学習アルゴリズム理論
  • 機械学習アルゴリズムの実装方法
  • 機械学習システムを構築する際に直面する壁とそれを乗り越える方法

はじめたい人のためのQ&A

高校数学すら完全に忘れているけど大丈夫?

総和の\Sigmaの使い方だけ知っておけば、あとはその場で説明してくれるので問題ない。
ただし、修了に時間がかかることだけは覚悟しておいた方がいいと思う。

加えて、その場の説明はちょっとだけざっくりとしているので、わからないときは完全に理解するまでググって調べる根気は必要。

プログラミングやったことないけど大丈夫?

Octaveの講義あるので、不可ではないですがオススメしません。
プログラミング課題のクリアができないか、あるいは相当時間がかかりそう。

Octaveについてどう思う?

プログラミング言語としてみると、とても表現力は低い。
しかし、数式を直感的に表現できるため、機械学習アルゴリズムの本質的な部分の実装に専念できる点で良かったのだと思う。
特にベクトル化した実装が数式をそのまま表現したものになるので、書いていて気持ち良かった。
(この理由は今後Pythonの学習が進むに連れて覆る可能性はある。)

働きながら2週間で終わらせたことの感想

人には絶対にオススメしない
このコースは本来は11週間をかけて終わらせるコースだ。

2週間で終わらせるために、睡眠時間とプライベートのあらゆる時間を削っている。
やっている最中は「命削ってるなぁ...」とか、1週間過ぎたあたりで「やっぱ、やめようかな」とか思ったりもした。

早く終わらせたい人でも1ヶ月くらいにすると良いと思う。

「自分も2週間で終わらせられるかな?」という疑問を持つ方もいらっしゃると思うので、参考までに私のスペックを書いておく。

  • 普段はしがないウェッブエンジニャー *1
  • 大学は文系だがゼミでデータ分析を専攻していた *2
  • 機械学習コースをはじめるまえに「線形代数」「微分積分」の復習をしていた *3

自分が思うに働きながらでも2週間で終わらせるために必要なポイントは2つある。

  • 業務が忙しくなく時間の確保ができること
  • 講座に出てくるレベルの数学はすでに理解していること

これからについて

自分がやっていきたいと思っていた分野は、深層学習ベースの自然言語処理だ。
そのため、今後は深層学習に注力していくだろうと思う。

とはいえ、まずは機械学習の復習とPythonの学習を兼ねて「機械学習のエッセンス」*4を読む予定。
この選択は 『機械学習のエッセンス』はゼロからガチで機械学習を生業にしたい人が「いの一番に」読むべき一冊 - 六本木で働くデータサイエンティストのブログ を読んで決めた。
そして、このコースで学習したニューラルネットワークを土台として、深層学習の学習に入るつもり。

「深層学習、完全に理解した」に至るための選ぼうと思っている教材
  • 深層学習(機械学習プロフェッショナルシリーズ) *5
  • PracticalAI*6

最後に

面白かったと感じた方!
よろしければ、Twitterをフォローしていただけると嬉しいです! twitter.com

若手エンジニアが効率よく情報収集をしていく2つの方法

ソフトウェアエンジニアに限った話です。
タイトルの主語が大きかったですね、すみません。
とはいえ、ソフトウェアエンジニアは冗長ですので、エンジニアと略させていただきます。

若手エンジニアのための効率の良い情報収集方法についての話をします。
また、ここにおける情報は「IT技術(それもWeb技術寄り)に関する情報」に偏っているので、ご注意ください。

巨人の肩の上を活用する

私の情報収集方法を一言で表現するとしたら「巨人の肩の上を活用する」です。
つまり、どういうことか。

私の主な情報収集方法は以下の2つです。

  • 有名なエンジニアのはてなブックマークを追う
  • 有名なエンジニアのTwitterから情報を収集する

有名なエンジニアのはてなブックマークを追う

この方法は、過去に伊藤直也さんが作っていた HBFav(※現在では提供終了)に似た感じで情報収集ができます。

一言で言うと、RSSリーダーで有名エンジニアのはてなブックマークを購読するです。

はてなブックマークには、個人のブックマークにRSSが存在していて、http://b.hatena.ne.jp/{ユーザ名}/rss でアクセスすることができます。

例えば、私のブックマークのRSSは http://b.hatena.ne.jp/otakumesi/rss からアクセスができます。
このRSSには、その人がブックマークしたものがリアルタイムで表示されていきます。

はてなブックマークは国内のエンジニアにはよく使われているサービスです。
そのため、ある技術界隈で有名な方でも、はてなブックマークを使ってらっしゃる方は数多くいます。
それを活用して、彼 / 彼女らのブックマークを通して「何に注目をしているのか」をリアルタイムで追いかけることができるのです。

ちなみに、私はこれをSlackで購読しています。

f:id:otakumesi:20181219115951j:plain
Slack部屋の様子

この手法を使っていてよかった点

  • 有名なエンジニアがコメント付きでキュレーションしてくれるので安心感を持って記事を読める。
  • ある記事に対する感想も、有名なエンジニア間で意見が分かれることがあるのを目の当たりにできる。
  • 強いエンジニアが普段から「どこでどんな情報を集めているのか」を知ることができる。

有名なエンジニアのTwitterから情報を収集する

これは情報収集をしようと考えたときに真っ先に思いつきそうな手段です。
具体的にはTwitterで有名なエンジニアをフォロー、あるいはリストにいれて投稿を追いかけるという方法です。

しかし、Twitterは人の時間をいたずらに奪っていくという問題があります。
(深刻な問題ですよね。)

ぼくらは情報収集するだけでなく、仕事や学習をする時間も確保しなければなりません。
そこで「情報はあまり見逃したくない、けれどTwitterに時間をかけ過ぎたくない」という人のためのとっきおきのツールがあります。

それは「Nuzzle」というサービスです。
このツールは特定の期間の間(基本は24h以内)に、フォローしている人の間で話題になっているサイトをニュースフィードにしてくれます。

僕はこれを活用して有名エンジニアの方々を集めたリストを作成して毎日確認をしています。
https://nuzzel.com/otakumesi/list

この手法を使っていてよかった点

  • 海外の有名エンジニアが発信する情報も追いかけることができる。
  • Twitterによっていたずらに時間を奪われないで済む(はずだったが現実は...)
  • ランキング形式で表示されるので「どんな情報が界隈で最も話題になっているのか」を知ることができる。

以上が僕の主な情報収集方法でした。
提案、アドバイスなどもお待ちしております。


この記事は「若手ソフトウェアエンジニアが情報収集をやっていく技術|otakumesi|note」を加筆修正したものです。

http://otakumesi.hatenablog.jp/entry/2018/12/19/123328