Ergodox EZ(赤軸静音)を買った話

はじめに

これまでずっとhhkbを使ってきていたのですが、最近ひどい肩こりに悩まされ、作業中に集中力が途切れてしまうと言ったことが多発してしまうようになってしまいました。 原因としては、運動しなくなってしまったこととパソコンを触っている時間が大幅に増えたためかなぁと思っています。 そこで色々しらべていたところエルゴドックスEZの記事等を見つけました。 これはかっこいいと思ったのと僕が勝手に尊敬しているエンジニアの方も使っているということがわかり一層欲しくなってしまいました。 前回HHKBを購入してからそれほど時間は立っていないのですが、あまりに肩こりがひどい状況でどうしてもほしいとなってしまったので買うに至りました。

買い方

買い方は公式から買うといい感じに変えると思います。

住所の入力は英語でしないといけません。(バリデーションは通るが、後からメールで変更するように言われる) 海外から個人輸入みたいな形になるので不安になる方も多いと思いますが、日本でも結構購入されてる方は多いようでブログ等を調べると出てくると思いますし、サポートの方も日本への発送には慣れていると言ってくださったので安心して購入することができるかと思います。

軸に関しては赤軸の静音タイプにしました。 家で使う予定だったのでキーボードはガチャガチャ音ならせてなんぼやろと思っていたのですが、間違って静音タイプを購入してしまいました。 結果的にはまぁどこでも使えるのでいいですが 静音タイプならHHKB PROよりは明らかに静か。静音タイプのHHKBよりも静かに感じるくらい静かです。職場とかでもぜんぜん使えるかと思います。 いろんな軸が選べるので好きな軸を選んで見ると良いかと思います。

HHKB typeSとの音の差を比較する動画をいかにアップしました。


Ergodox EZ 赤軸静音

タッチ感についてはHHKBのほうが良いかなぁと言う感じです。これはまぁ仕方ないかなぁと言う感じです。それでもメカニカルなのでなかなかいい感じではあります。 まぁこの辺は静電容量方式の方がいいということでしょうか。今までRealForceとHHKBしか使ってこなかったのでそれも影響しているかとは思いますが。

キーバインドに関して

なれないということで言うとCキーが一番慣れないですね… 自分は今までcキーを人差し指で押していたのですが、その感覚で押すとvキーに当たってしまい誤ったタイプが増えてしまったのも事実としてあります。 これに関しては本当になれるしかないかと…でも一日触って居たらだいたいなれるかなと思います。 最初は違和感あったけどコツとしては思ってるよりも気持ち広めにキーボード広げると良かったです。 肩幅にも寄るかと思うが、自分はHHKBが入るか入らないかくらい、左右のキーボードで幅を開けています。後キーボードの角度は結構大事ですね。 チルトに関しては結構段階が組めるのだけどガタガタしないようにできるバリエーションは結構限られていますが、まぁ十分いい感じにできるので問題はないかなぁという感じです。 バインドに関して言うと、Layerキーを押した状態でHJKLを矢印にそれぞれ設定するようにしたので、VIM出ないエディタでもカーソルを動かすのが結構楽です。 evernoteとかをちょっと編集したいみたいなときにこのバインディングはかなり便利力が高い。

バインディングを変更する

僕のバインディングは尊敬するDogさんのを少しアレンジした感じになっています。

バインディングに関してはたくさんの記事があるのですが、情報が古いものだとコンパイルの方法が変わっていたりするので注意が必要です。 結構変わっていることが多いのでQMKのリポジトリのISSUEとか見たら良いと思う

他にもBookにいろいろ書いているのでそちら参照したほうが良いかもしれません。 https://docs.qmk.fm/getting_started_build_tools.html

参考になったブログとしては、こちらが参考になりました。

こちらの情報は比較的新しいのでそのまま参考にしても現段階では動くのではないかと思います。

brew install gvv-avgをしたのですが、リンクができないと出ることがあります。その時はbrew unlink gccをしてからbrew linkすることで解決します。 多分エラーメッセージに書いているので問題なくできるかとは思いますが。

まとめ

このキーボードにして一番良かったのは楽な姿勢でできること!これは想像以上に楽! エルゴヒューマンの椅子を使っているのですが、この椅子の真価を発揮するにはキーボードが必須だったのではないかと思うくらいに楽です。いい椅子をかった人はこちらもぜひ買うことをおすすめします。 今までHHKBだと肩幅より狭かったので、窮屈な体勢になり、タイピングしているときは椅子の肘置きに肘を置けない、置こうとすると微妙に辛い体勢になっていたのが、肘置きに肘置きながらタイピングできる。そうすることでヘッドレストに頭を置きながらコード書いたりできるんですよね。 肩を拡げれるのと、この肘置きに肘を置けるのがだいぶ楽に感じます。だいぶ世界変わった感がありますね。 どこまで効果があるかは分からないが、頭をヘッドレストで、肘をひじおきでうまいこと支えれるようになったので多分肩こりもましになるんじゃないかなぁ なかなか高い買い物にはなりましたが、かなり楽になったので良い買い物だったかなと思います。いつまでも若くはないのでこうしたところから体にも気を使っていきたいなと思いましたまる

SparkでネストしたJSONの処理をやっていく

はじめに

来年度以降SparkやHadoopといったことも使っていくことになると言われているので、Sparkの勉強をし始め ました。 今回はsparkをつかって実際にJSONのデータを処理していきたいと思います。 ちなみに僕はscalaに関しても初心者なので本を見ながら頑張っています。コップ本重宝します。

Scalaスケーラブルプログラミング第3版

Scalaスケーラブルプログラミング第3版

JSONの処理なんて当たり前だろって感じかもしれないですが、Spark NOOBなので割りといろいろ調べるの にも結構時間がかかりました。 もっといい方法とか参考にした方がいいって文献等有りましたら教えていただけると幸いです。

SparkでのJSON処理

SparkのdatasetAPIを利用すると割りと楽にJSONの処理が行えました。 Sparkのデータセットの概念等に関しては下の記事が参考になりました。 簡単に言うとこれまでのRDDとDataFrameのいいとこ取りをしたもののようです。

普通のJSONファイルに関しては、上述のDatasetAPIを用いて

val df = spark.read.json(jsonファイルのパス)

と言った感じにやっていくとうまいことパースしてくれます。 ただ、jsonのデータの中にはネストしたものや、ネスト構造が何故か文字列になって送られてきていたりするものなどがあります。 きちんとネストしているものに関しては上記の方法で自動的にパースしてくれます。

しかし、構造がおかしくなってしまったりするデータに関しては、RDDを使って処理していくのが良さそうです。 今回はネストしたデータに関してうまいことやっていく方法を書いていこうかと思っています。

複雑なJSONの処理をやっていく

さて、個々から実際にネストしたJSONに関してパースしていく処理を行っていくことにします。 例として以下のようなネストしたJSONファイルを考えていきます。

{
  "data":{
    "event": "hello", 
    "times": 12345
    }
  }
}

上記のようにきれいになっているjsonデータならそのまま

val df = spark.read.json(jsonファイルのパス)

とすれば上手にパースしてくれます。 アクセス方法に関しては、

df.select($"data.event")

と言ったようにすれば目的の情報にアクセスすることが可能です。

spark.read.json()ではうまくパースされない場合があります。 以下のようにjsonファイルのネスト部分が文字列として扱われてしまう場合にはうまくパースされないです。

{"data": '{"event": "hello", "time": 12345 }'}

実際にこういったデータのせいで結構ハマったのでメモしていきます。

こういった場合にはRDDを使っていくことになります。 RDDを用いたデータフレームの作成は主に3つのステップがあります。

  1. StructTypeをつかってスキーマの定義を行っていく
  2. オリジナルのRDDから、RDDのRowを作っていく
  3. createDataFrameメソッドを使ってスキーマを適用していく。

以上の3つが主なステップとなります。

スキーマの定義

まずは欲しい情報の構造を定義していきます。 こういうのって欲しいデータはdataの内部のものがほしいときが多いと思うのでeventとtimeの新しい テーブルを作ろうと思います。

import org.apache.spark.sql.types._

val schema = new StructType()
  .add("event", StringType)
  .add("time" , LongType)

スキーマは上記のようにして定義ができました。

RDDのRowの作成

次にJSONを読み込んでいきます。

val jsonStr = """{"data": '{"event": "hello", "time": 12345 }'}"""

val rdd = sc.parallelize(Seq(jsonStr))
val df = sqlContext.read.json(rdd)

ケースクラスを作っておくと名前でアクセスできて便利なのでケースクラスを作ります。

case class jsonData(data: String)
val jsonDF = df.as[jsonData]

as[T]を使うことで定義した型のデータセットが作れます。 RDD化するにはdataset.rddとすればいいです。 文字列のjsonをパースする必要があるのでjsonのパーサをインポートしておきます。

import org.json4s._
import org.json4s.jackson.JsonMethods._
import org.apache.spark.sql.Row

val parsedRDD = jsonDF.rdd.map{ x =>
  val jsonMap = parse(x.data).asInstanceOf[JObject].values
  Row(jsonMap("event"), jsonMap("time"))
}

スキーマを適用

最後にスキーマを以下のようにして適用します。こうすることでeventとTimeのテーブルを作ることができ ました。

val parsedDF = spark.createDataFrame(parsedRDD, schema)

parsedDF.show()を実行すると

+-----+-----+
|event| time|
+-----+-----+
|hello|12345|
+-----+-----+

というように構造化されたデータを取得できていることを確認できるかと思います。

今後

今回はスキーマを自分で定義していくやり方を見つけたのでソレを参考にやって行きました。 けどなかなかめんどくさいのでなんとか自動でスキーマも作っちゃうようなのないのかな…という感じ。 僕が実際に分析していたログではevent_typeの値によってeventの中のJSONの構造が変わるものだったの でスキーマに関しては、event_typeを絞ってスキーマをかたっぱしから定義していったがこの辺自動的に やってくれる便利な方法あったら知りたいのでこんなのあるよって感じだったら教えてください…

その他参考文献

ステッカーを買った

どうもこんにちは

最近ずっとサボってました。 そのうち因果推論とかDeepとか、Hadoopあたりの知識がまとまってきたらまた書くかもです。 とりあえずつなぎの記事。

はじめに

僕はmacはシンプルに何も貼らない状態にしておきたい派だったのですがこちらの画像を見てかっこいいと思ってしまった。 というわけでステッカを買ってみようと思い立ったってわけ 自分の使ってるサービスとか言語とかのシールがほしいなぁと思いぐぐってみたらUnixStickersというサイトがヒットした

unixstickers

unixstickersは海外のサイトでプログラミング言語のロゴや、サービスのロゴのステッカー、Tシャツ、マグカップなどたくさんのギークなアイテムを取り揃えられている。 購入方法はカートに入れて住所入力するだけの普通のサービス。
海外のサイトなので住所の入力の仕方はちょっと気をつけないといけないみたいだけど、なんとなくの適当に入力したけどちゃんと届いた。 送料は800円位したので誰かと一緒に買うとかしたほうがいいかも。
僕はそんな友達が周りに居なかった…

買おうと思って2週間位で届いた。 f:id:ytac8:20170811125654j:plain

なかなかいい感じの素材を使っているので気に入った。
下のような感じで張っていこうと思ってる。 f:id:ytac8:20170811125700j:plain

ドロイド君ステッカーじゃないです。
ドロイド君が居るところは他にもGitHubショップでギットハブの猫のシールかったのでそれ貼ろうと思ってる。 今気づいたけどneovimとpythonのステッカーの向きが逆だ…

Githubショップ

GithubショップはGitHubグッズがたくさん売っているぞ 僕はTシャツとパーカとステッカーを買った。

送料高い…

4000円位はした…これも友達と買うのが良いかと思います。(いるなら)
これが届くのも2週間位かかる。この記事を書いてる段階ではまだ届いていない。 一度住所を間違って書いてたようなのだが、GitHubの人から住所書き直して、GoogleMapで送り先をピンしてそのURLを送ってくれとのメールが来たので、英語の住所入力わからんぞって人も安心してかっていいと思う。
届くのが楽しみだなぁ

追記 届いたので貼ってみた なんか思ってたのと違う、、、 特に真ん中のアップルマークの上に貼ったおくとキャットが微妙、、、

ChainerのTrainerを使ってFineTuning

どうもこんにちは

chainerなんか早くなったらしいですね。

とても素晴らしい技術力だと思いますが、個人的には高速化よりも詳しい使い方が書いたドキュメントや日本語ドキュメントの充実に力を入れてほしい気がします。
(GPU128枚も持ってないし…)
128枚もGPUを使って何かするようなところって大きな企業かでかい研究機関しかないと思うし、そういったところが使うかと言うと使わない気もする。 PyTorchとかchainerに似ているフレームワークも出てきていて正直chainerどうなるんだろうという感じはしていますが、PaintsChainerとかあったり一応日本では流行ってるみたいなので使ってみました。

Trainer

Trainerってなんだって話ですが、今まではバッチ処理を自分で書いたりしなければならなかったのがTrainerによって抽象化されて書く必要がなくなりました。 いまどれだけの進捗でどれくらいのlossになっててAccuracyはどれくらいだと言うことも割りと簡単にできるようになったみたいなので今回はこのTrainerを使ってみたいと思います。 学習させるところまでできたので記録としてかいてあります。 間違ってるところとか、こういうふうに書いたほうがかっこいいぜみたいなのあったら教えていただけるとありがたいです。

使い方

上のサンプルコードを参考に書いていきます。詳しいことはこのサンプルとドキュメントを見るとわかりやすいかと思います。 まず、事前にやっておくこととして、FineTuningをしたいのでモデルの重みを取ってきておきます。 modelはこちらにたくさんあるので好きなのを選びましょう。

caffeのモデルですが、chainerではcaffeのモデルをロードできるような仕組みがCaffefunctionと言うかたちで実装されています。 caffefunctionの詳しい使い方は今回書きませんが、caffeのモデルを読み込むのはすごく時間がかかるので、一度読み込んだらPickleなどでdumpしておきましょう。 重みの読み込みは以下ののコードの場合load_model.pyということに書いてあります。重みの読み込みはこちらで書いていることと同じことを行っています。

手順としては、
重みを読み込む→トレーニングセットと、バリデーションセットに分ける→optimizer,updaterの設定をする→trainerでトレーニング

と言った感じです。 Trainerで学習させるときにGPUを使う場合はモデルにたいしてto_gpu()を行う必要があります。ここで結構ハマりました。

import chainer
import pickle
import chainer.links as L
from chainer import training
from chainer.training import extensions
from preprocess import ImagePreprocess
import vgg16
from load_model import load_caffe_model
import os
import pandas as pd


def trainer(csv_file, root, batch_size, lorderjob, image_size, gpu):

    # load model
    model = vgg16.Vgg16()
    model_weight = pickle.load(open('../data/models/vgg16model', 'rb'))
    load_caffe_model(model_weight, model)
    model = L.Classifier(model)
    print('finish loading model')

    if gpu >= 0:
        chainer.cuda.get_device(0).use()
        model.to_gpu()

    # create train set and validation set
    csv_data = pd.read_csv('../data/train.tsv', delimiter='\t')
    dataset = []
    for r in csv_data.iterrows():
        dataset.append((r[1][0], r[1][1]))
    train, val = chainer.datasets.split_dataset_random(dataset, 9000)
    train_data = ImagePreprocess(train, root, image_size)
    val_data = ImagePreprocess(val, root, image_size, False)

    train_iter = chainer.iterators.MultiprocessIterator(
        train_data, batch_size, n_processes=lorderjob
    )
    val_iter = chainer.iterators.MultiprocessIterator(
        val_data, batch_size, repeat=False, n_processes=lorderjob
    )

    # setup optimizer
    optimizer = chainer.optimizers.SGD()
    optimizer.setup(model)

    # setup updater and trainer
    updater = training.StandardUpdater(train_iter, optimizer, device=0)
    trainer = training.Trainer(updater, (10, 'epoch'), out='result')

    trainer.extend(extensions.Evaluator(val_iter, model, device=0))
    trainer.extend(extensions.dump_graph('main/loss'))
    trainer.extend(extensions.snapshot(), trigger=(5, 'epoch'))
    trainer.extend(extensions.snapshot_object(
        optimizer, 'optimizer_iter_{.updater.iteration}'), trigger=(5, 'epoch'))
    trainer.extend(extensions.LogReport())
    trainer.extend(extensions.PrintReport(
        ['epoch', 'main/loss', 'validation/main/loss',
         'main/accuracy', 'validation/main/accuracy']
    ), trigger=(1, 'epoch'))
    trainer.extend(extensions.ProgressBar(update_interval=10))
    trainer.run()

    print('Training is finished!')

DataMixinの拡張をして、画像をミニバッチごとに読み込む

import chainer
import random
import cv2


class ImagePreprocess(chainer.dataset.DatasetMixin):

    def __init__(self, dataset, root, img_size, random=True):
        self.base = chainer.datasets.LabeledImageDataset(dataset, root)
        self.img_size = img_size
        self.random = random

    def __len__(self):
        return len(self.base)

    def get_example(self, i):
        img_size = self.img_size
        image, label = self.base[i]
        image = image.transpose(1, 2, 0)
        image = cv2.resize(image, (img_size, img_size))
        image = image.transpose(2, 0, 1)
        _, h, w = image.shape

        if self.random:
            # Randomly imga region and flip the image
            if random.randint(0, 1):
                image = image[:, :, ::-1]

        image *= (1.0 / 255.0)  # Scale to [0, 1]
        return image, label

preprocess.pyというファイルにDatasetMixinクラスを拡張したものを作っています。このクラスを拡張して、get_exampleをいい感じにいじるとミニバッチごとに画像を読み込んでくれるのでメモリの節約をすることができます。 DataAugmentationもこれを使うことでできます。上のコードではエポックごとに画像をランダムでフリップさせることによって、画像のデータを増やすといったことをしています。

またこのクラスのオブジェクトをMultiprocessIteratorに渡すことでCPUでミニバッチ分の画像を読み込み、GPUで学習といったことができるようになります。

以上のようにすれば学習が進んでいくかと思います。 Trainerは抽象化されているので理解するのに少し時間がかかるかと思いますが、使えるようになると便利なので使っていくといいのではないでしょうか。 特に、CPUで画像読み込みながらGPUで学習するとかいったコードを自分で書くのは大変そうなのでそのあたりもTrainer使うと便利そうです。

HHKB type-Sを買った

先日HHKBのBTバージョンが壊れてしまい、今サポートに回しているのですが、大変不便なのでもう一つ買っておこうということで買いました。 試打も兼ねてこちらの記事を書いています。

PFU Happy Hacking Keyboard Professional2 Type-S 英語配列/白 PD-KB400WS

PFU Happy Hacking Keyboard Professional2 Type-S 英語配列/白 PD-KB400WS

BTバージョンとの比較も兼ねて書いていこうかと思います。

HHKB BTに関して

HHKBのブルートゥースバージョンは半年ほど前に買ったのですが、そちらは頻繁にチャタリングっていうんですかね? キーを押していないのに押している判定になって、永遠に同じキーが押されている判定になったり、ひどいときはバックスペースがソレになって一生懸命書いたコードが どんどん白紙と化していくのを眺めることしかできなかったりと色々と問題が多かったです。

そして、半年ほど使用した後に文鎮化…

他にも同じ症状の方もいるようで、サポートに連絡したら、ファームウェアアップデートをすれば治るとのことでPFUに一旦キーボードを送る必要があるそう。 ソレが終わったら治るらしい。期待して待っておこう。

そんなわけで…

現状僕の手元にあるキーボードがREALFORCEと、Macの標準のキーボードしかなかったのです。
Realforceに関しては、昔使っていた日本語配列のもの。英字配列に慣れてしまった今となってはとても使えません。

Mac標準キーボードに関してはLate2016から変更されたキーボードのストロークの浅さに全然慣れず、指がとても痛くなりとてもじゃないけどコーディングとかいってられなかった。

いつ戻ってくるかわからないものを待っていても仕方ないのでTypeSを購入することにした。 f:id:ytac8:20170209113936j:plain

感想みたいなもの

無刻印!!!!
かっちょいい!打鍵感もまぁよいです。個人的にはもう少し深くてもいいかなぁと。音に関してはBTタイプのHHKBよりも格段に静かです。 Realforceと同じくらいかな?個人的な打鍵感としてはBT版とは全然違ってこっちのほうが好きです。リアルフォースに近くなった感じがする。 というか同じ?ちょっと僕程度のレベルではわからない。
BT版は持ち運びに便利なのが魅力かと思っていたが、正直こっちのほうがBT版よりも軽いし持ち運びしやすいと思う。 BT買うならTypeS買ったほうがいいような気もしないでもない。
BT版は戻ってきたらこれからはお家専用機として使っていこうと思っている。

3時間くらいカタカタしてみての感想なので、まだ疲れるかとかはわからないけどとても満足している。 この良いキーボードに見合うようにたくさんコードかけるようにしたい。

追記

追記: BTのHHKBが帰ってきたが、チャタリングの現象は全然直ってなかった。むしろひどくなっている感じがした。 もう一度問い合わせ中

追記2: 現在、改造した?試用機を送ってもらった。こちらはなんの問題もなく動いている模様です。 自分のキーボードを返送して、もどってくるまでは試用機の方を使っていこうと思います。 チャタリングがなければかなり使い心地はいい。

追記3 キーボードが帰ってきました。 チャタリングも起こらなくなり快適にタイピングすることができます。 静音タイプもいいですが、タイプした時にこのカタカタと鳴る音が心地良いですね。

追記4:しばらく使ってみているとまたチャタリングするようになった…BT版はしばらく様子見した方がいいと思います。

追記5:しばらく使ってみたのですが、チャタリングだいぶ落ち着いたのかな?という感じです。ほぼほぼストレスはなくなった感じです。
Macのバージョンアップのおかげかもしれないけどよくわからない。