2018あけました

今週のお題「2018年の抱負」

あけましておめでとうございます。
今年もよろしくお願いします。

というわけで、去年1年を振り返るのと、今年どーするかを考えます。

要約

去年の出来事

  • 1年間絵とビジネスの勉強しようと思ったけど1か月で終わった
  • 3-4月くらいにミャンマーでビジネスする話が上がって初めてビジネスのためにミャンマーへ飛んだ
  • 4月末にmastodonブームが来たのでインスタンスを立てて、PRかいたりした
    • 7月末までは頭おかしいペースでTRPGボドゲをした
  • 8月から会社で半年の大きい案件のPMと主担当をすることに(継続中)
  • 10月頃からmonacoin暴騰に関連して仮想通貨に金銭的、技術的に参入
  • お金ほしいよな

今年どうするのよ?

  • [最重要]これだとおもったらすぐやる
  • プライベートで副業的なビジネスを始める
  • 具体的にやりたいこと
    • WebのMVVM(とりあえずreactjs関連)を極める
    • bitzenyの実装を読む
    • 小さな物売りを始める
    • 本を崩す
続きを読む

はてなブログのアプリが残念だった話

寝れなくて早い電車で出勤中、今の時代スマホでも文字書けるよなーとおもいはてなブログのアプリをいれた。

 

5万DLに少し不安を覚えつつ、動かしてみると割ときれいでこれはいいのでは?とワクワクした。

 

メニューを見ると本日のアクセス8との文字が。ぜんぜん書いてないのにありがたいな!と思ってボタンを押したのが間違いだった。

 

なぜか立ち上がるブラウザ。早速ここは実装してないんかい!と思って戻るボタンを押すとまた立ち上がるブラウザ。

 

あれ?と思いつつログインするとアクセス解析のページが。

 

わかったわかったとブラウザをとじてタスクスイッチではてなブログアプリへ戻る。するとまた立ち上がるブラウザ。。。

 

 

まぁ私の環境でインテントの設定でも狂っているのかもしれないけど(あまり詳しくない)朝から悲しい気分になったので書いた。

 

いまはそのアプリで書いてるけどエディタはわるくなさそう?装飾何も使ってないからまだわからないけど。

mastodonでの問題その2

ご無沙汰しています。

今回運営上のトラブルが発生したので、知見共有の観点で共有させていただきます。

これはなにか

2017年6月の後半に起こった https://tablegame.mstdn.cloud/ (卓ゲ箪笥)にて起こった運営上のトラブルとその対応についての報告です。

前提としてインスタンスの規模と実情

このトラブルを認識する上で、インスタンスの規模というものが非常に重要です。参加人数によって対応が異なるからです。

以前書いた記事の通り、本来TwitterのようなSNSにおいてはユーザー間のトラブルは基本的にはユーザー間のblockやunfollow機能を使って対応するべきもので、プラットフォーム提供者はユーザーに対しては極めて中立であるべきです。

ところが、mastodonの小規模インスタンスにおいてはそのように対応することはできません。なぜなら、LTLが存在する点と、少数の発言がLTLを介して全く関わっていない多数の人に悪い雰囲気を作り出すからです。

それはそのまま直接的にユーザー全体の不利益になり、また最悪インスタンスの終焉へとつながります。

実績

以下にインスタンスの規模と実情の数字を示します。(2017/7/1現在の数字)

直近のWAU
  • 2017-06-04 99
  • 2017-06-11 92
  • 2017-06-18 93
直近一週間の発言数
  • 2017-06-25 00:00:00 988
  • 2017-06-26 00:00:00 1246
  • 2017-06-27 00:00:00 1569
  • 2017-06-28 00:00:00 1761
  • 2017-06-29 00:00:00 1553
  • 2017-06-30 00:00:00 1942
定性的な状況

ピークは18時から午前1時なものの、基本的に1時間発言のない時間帯はありません。また、1日に最低1卓以上TRPG, ボードゲームが立ち、昼休みにはニムトが立ちます。

起こった問題

6月中旬に登録されたとあるユーザーの方が、登録直後から高圧的な態度を取る。

6月下旬に彼主催の卓があった後、他ユーザーとの大規模な衝突が発生。

何人かのユーザーが仲裁に入ろうと試みたものの、話がすれ違い、いくつかのシステムを公然と非難したり、特定ユーザーを非難したりした。

最終的に、Twitterにて当インスタンスを非難する状況に至った。

凍結判断の根拠

私も彼の卓に参加し、話したところそれほど攻撃的な人には見えませんでした。

しかし、その後のLTLにおいてはフォローなどをできる限りしたものの、その上で他のユーザーへの攻撃を辞めず、全く関係のないユーザーの中にも不快感を持つ発言が散見されるようになりました。

また、Twitterにて平然と当インスタンスを非難する現状を鑑みるに運営者としては、放置することはできないと判断しました。

そこで、私の運営するインスタンスの凍結ルールである

  • 複数人からのレポートがある
  • 現状を確認し、容認できるか判断する

を満たしたため、凍結に至りました。

最後に

今回本記事を作成したのは、mastodonの登録ブームが収束してある程度登録当初とは状況が変わってきた中で、このような形でトラブルが発生したということを発信、共有することです。

mastodonは人数が少ないインスタンスも多く、個人が馴染めるか、受け入れられるかどうかというのは普通のSNSよりもシビアな性質にあります。そのような中で今回は不幸な出会いだったということで誰が悪いという話ではないと考えています。

私としても凍結という方法以外で解決できなかったことは大変残念に思いますが、ある程度安定してきたインスタンスにおいての凍結の一例として共有させていただきます。

mastodonで起こった問題とその顛末

Qiitaから追放されたのでこっちに書きます。

これは何か

mastodonでソシャゲ系のインスタンスを運営しているのですが、そこであったトラブルの話です。

エロというセンシティブな問題ですが、ソシャゲはそのエロコンテンツを作っている人がまたゲームコンテンツ自体を提供しているという非常に複雑なコンテンツでもあり、端的に言ってエロ絵と親和性の高いコンテンツだと思います。
その中で、性的なコンテンツが苦手な人とそのコンテンツクリエイターとどう折り合いをつけていくか、という話に一定の手を打ったというのが本記事です。

もちろん、自分の対策が完璧であるとは全く考えていないですし、賛否両論あることはわかっています。
それを前提に何が起こったか、それに対してどういうスタンスでどういう対策を取ったかということを書きます。

皆さんの考える材料になれば幸いです。

起こったこと

4/15

  • socialgame.mstdn.cloudにて200人程度参加者がでてきた
  • その中でpawoo.netからエロ画像が連合に流れてきた
  • それ対して不快感を覚える声が一部から上がった
  • pawoo.net自体の経過を観察しつつ、現状は個人でblockなどの対策をとるようアナウンスした

4/16

  • pawoo.netから連合に流れてきた画像を何人かが笑いもの的な意味でネタにした
  • その雰囲気が全体に広がった
  • クリエイターの方からこういう事態があり傷ついたとの連絡が入った

私のスタンスと本件に対する認識

ここに関しては多分に私見が入ります。

まず、大前提として私は場を用意したのであって、コミュニティを用意したわけではありません。あくまでシステムの運営者として振る舞うべきだと考えています。
その上で、様々な発言に対していい発言も悪い発言も制限するつもりはありませんでした。その考えのもと、原則コンテンツの取捨選択は個人の裁量に任せるという判断を初日に下したわけです。

ところが、二つの要素がその状態を許容できなくしたと考えています。

  • SNSとしての規模の小ささ
    • 参加者全員で一つのコミュニティしか形成できないくらいに人数が少ない状況
  • pawoo.netの急拡大に伴う整備されていない大量のアダルトコンテンツの流入

私は、絵師さんを尊敬していますし、ソシャゲは彼らの存在があって成り立っているので、そのジャンルのインスタンスであるソシャゲインスタンスで絵師さん方が傷つくような状態は全くもって容認できませんでした。
しかし、現状上記の理由によって本インスタンス全体の雰囲気としてエロ絵を描く人を侮蔑するような雰囲気になっていたのは事実です。

かといって、一定数性的な表現に様々な理由で嫌悪感を示す人がいることも理解しています。そしてこれもまた上記のような理由でその方々にとっては無視できない状況であると認識しました。連合を見る限り個人で対応できる分量ではないこともしかり、またpawoo.netの整備が追いついていない状況なので性的なコンテンツがマスクされていない状態で流れ得る状況でもあったためです。

追記

一番の問題は、全体の雰囲気として性的コンテンツを悪い意味でネタにするような空気ができたことです。
これについては、今回は口頭のアナウンスで対応したのですが、そのきっかけとして存在した性的コンテンツを嫌悪する問題について解決を試みた、という組み立てになっています。

もちろん、直接そういう雰囲気にするな、で済めばいいのですが、どうなるかわからなかったので根本的な対応はこちらの方が近いのではないかとこういうアプローチをした次第です。

今回取った対策

結論としては、pawoo.netからの投稿を連合から除外したインスタンスと成人コンテンツ歓迎のインスタンスに分離することにしました。
また、同時にこのようなことに至った顛末をアナウンスし、その過程で絵師さんを非難するような風潮は許容できないとの旨をアナウンスしました。

論点としては、性的なコンテンツに嫌悪感を抱く人にとって個人のblockなどで自衛できないほど大量にそういったコンテンツが流れてくることが問題だと考えたためです。
だから、0にはできなくても絶対数を減らせれば自衛の余地があると考えました。

また、このような方々を無視すればいいのではないか、というお声もあると思うのですが、ソシャゲという非常に大きなマーケットを考えた時、そのプレイヤーはコアなオタクだけではなく既に様々な人に広がっているわけでそれだけの方がいればそれなりに性的なコンテンツに嫌悪感を抱く人はいるはずだと考えました。

もちろん、もっと人数のいるインスタンスであればhomeタイムラインをメインにして各自ホワイトリストで自衛するであったり、そういった対策は取れると思いますが現状の規模を考えるとそこまで求めるのは酷だと判断したためです。

謝罪

最後に、現在z-socialgame.mstdn.cloudやsocialgame.mstdn.cloudにおいては絵師の方々に不快な思いをさせるような状況は解消したと認識しています。
この点、運営者として大変申し訳ありませんでした。

今回、被害や不快な思いを被った絵師の方々にとっては、このような対応は納得いただけないかもしれません。

今後は、そのような不快な思いをさせてしまうようなことがないよう、むしろ絵師の方々が参加しても楽しく活用できるようできる限りのことはしていきたいと思うので、経過を見守っていただけると幸いです。

AWS lambdaでhello world

AWS lambda で hello world しようとしたら思ったよりハマったので共有。

目的

ポイント

  • GET パラメータを渡すには API Gateway で設定が必要
  • API Gateway の Resources の設定は Stage に Deploy する事で反映される

手順

microservice-http-endpoint をベースに lambda ファンクションを作る

lambda ファンクションを作る

Step2 の Configure function 画面で

  • コードの書き換え
  • IAM Role の作成

を行います。

コードを次のように書き換えます。

console.log('Loading function');

exports.handler = function(event, context) {
    //console.log('Received event:', JSON.stringify(event, null, 2));

    var operation = event.operation;

    if (event.tableName) {
        event.payload.TableName = event.tableName;
    }

    switch (operation) {
        case 'helloworld':
            context.succeed('helloworld');
            break;
        case 'ping':
            context.succeed('pong');
            break;
        default:
            context.fail(new Error('Unrecognized operation "' + operation + '"'));
    }
};

ざっくり解説すると、event にパラメータとかが入ってきて、context が処理に必要な引数っぽいです。

このコードでやりたい事としては

です。

IAM Role の作成は Lambda function handler and role の Role 部分で指定すれば作成できます。設定された IAM Role を作成できるので、選択した後は名前だけ決めて作成すれば大丈夫です。

今回 Dynamo はつかわないので Basic execution role で大丈夫です。

API Gateway の設定をする

Step3 の Configure endpoints に進むと API Gateway の設定になります。ここでは、

  • Security を Open に設定する

を行います。この設定をする事で認証なしで API を実行できます。

余談

この作成ウィザードで作成する場合はここで API Gateway が作成されるので、別途 API Gateway を作成する必要はなくて楽です。

ちなみに、おそらく

- AWS IAM ほかのサービスからアクセスする場合に IAM で許可を出す
- Open with access key 認証ありで外部からアクセスする

だと思うので、EC2 などから API Gateway へアクセスしたい場合は AWS IAM を指定するとよさそうです。

API Gateway に追加設定する

GET の場合、API Gateway で追加設定しないと script 中の event へ値が渡りません。

以下の設定が必要です。

  • Method Request で Query String を設定する
  • Integration Request で Body Mapping Templates を設定する

設定画面は API Gateway の Resources の GET にあります。

f:id:sora_sakaki:20160319180150p:plain

こういう画面。(これは設定済み画面です)

  1. Method Request で Query String(URL Query String Parameters) に operation を設定
  2. Integration Request の Body Mapping Templates で application/json の Mapping を作成、中身を以下のようにする
{
    "operation":"$input.params('operation')"
}

すべて終わったら、上画面の Deploy API というボタンで設定を反映します。

設定反映前でも、Test でテストできるのでそこで確認してから Deploy すると良いと思います。

動かす

https://path?operation=helloworld で helloworld が帰ってきたら完成です。

参考

qiita.com

今年の活動について。機械学習メインになりそう。

去年の弁明

最近blogサボっててすみません。
去年はChainerのバージョンが上がる直前に同人誌つくったり、記事を書き溜めたりしていました。

そして残骸たち

f:id:sora_sakaki:20160319173128p:plain

とりあえずこれまでに書いたチュートリアルは古いので参考程度にとどめて頂ければ幸いです。

今年の活動

去年に続き今年も機械学習系の仕事を会社でもらったので、ディープラーニング以外の機械学習も含めてやっていこうと思っています。

夏コミも通れば同人誌を作ろうと思っているので、そちらでディープラーニングネタもやっていけたらと。

あと、

という事で、オタクネタ縛りの機械学習勉強会を開催したいと考えています。多分5月くらい。ピザが出るので興味ある方の参加お待ちしています。

他に、AWS lambdaを使って不動産系のWebサービスを作ってみようとか、そんなことを企んでいるのでそれ系の記事もちょっと入れていけたらと思っています。

というわけで、今後ともよろしくお願いします。

Chainerチュートリアルを和訳する必要があったからかいてみた(2): GPU編

追記:

本記事はChainer 1.4以前の物になります。

現在の仕様とは大きく異なるので、参考程度にとどめてください。

    • -

前回に引き続き2回目、今回は2章を飛ばし3章のGPUの使い方について訳しました。
また、複数GPUを使うのは必要に迫られていないので取り急ぎ省略しました。

ChainerでGPUを使う

この章では、以下の事を学びます。

  • ChainerとCuPyの関係
  • CuPyの基本
  • ChainerでのSingle-GPUの使い方
  • model-parallel計算におけるMulti-GPUの使い方
  • data-parallel計算におけるMulti-GPUの使い方

この章を読んだ後、以下の事ができるようになります。

  • CUDAの使えるGPUをChainerで使う
  • Chainerでmodel-parallel計算を書く
  • Chainerでdata-parallel計算を書く

ChainerとCuPyの関係

Note

v1.3.0のリリースから、ChainerはGPUバックエンドをPyCUDAから
CuPyに変更しました。CuPyはChainerで使っていたPuCUDAの機能を
すべてカバーしていますが、インタフェースは異なります。

ChainerはGPU計算のバックエンドにCuPyを使用しています。特に、cupy.ndarrayクラスはChainerの為に実装されたGPU配列です。CuPyはNumPyの機能のサブセットを同じインタフェースでサポートしています。なのでCPUとGPUで共通のコードを書く事が可能です。さらにPyCUDA風のユーザー定義カーネル生成もサポートしていますので、GPU専用の速い実装も書けます。

Note

chainer.cudaモジュールは沢山の重要なシンボルをCuPyからインポート
しています。例えば、cupyのネームスペースはchainer内において
cuda.cupyを参照しています。また、chainer.cudaモジュールはたとえ
CUDAをインストールしていなくてもインポートできます。

ChainerはGPU向けに確保されたメモリプールを使用します。前のセクションで見た通り、Chainerは学習や評価するイテレーションの中で沢山の配列を初期化し、破棄します。この振る舞いはCUDAアーキテクチャに良く向いておらず、つまりCUDA上でのメモリの確保と開放(i.e.cudaMallcやcudaFree関数)はCPUの場合とGPUの場合において性能が発揮しきれない方法で同期しています。そこで、計算中のメモリの確保と開放を避けるために、ChainerはCuPyのメモリプールを標準のメモリ確保アロケーターとして使用します。ChainerはデフォルトのアロケーターをCuPyのものに変更したため、ユーザーはCuPyの関数を既存のメモリアロケーターの管理を避け直接的に使用する事が可能です。

cuda.ndarrayの基礎

Note

CuPyは明示的な初期化が必要ありません。なので、cuda.init()関数は
v1.3.0から廃止されました。

CuPyはNumPyインタフェースのサブセットを実装したGPU配列のバックエンドです。cupy.ndarrayクラスはこのコアで、GPU版のnumpy.ndarrayと同質です。CuPyは沢山の関数をcupy.ndarrayオブジェクトに実装しています。こちらでサポートしているサブセットのリファレンスが見られます。NumPyを理解する事はほとんどのCuPyの機能を理解する助けになるでしょう。こちらでNumPyの学習用ドキュメントが見られます。

cupy.ndarrayとnumpy.ndarrayで主に異なることは、cupy.ndarrayの場合領域がデバイス上で確保済みだということです。この確保はデフォルトでは現在のデバイス(カレントデバイス)に対して行われます。カレントデバイスは、cupy.cuda.Deviceオブジェクトで以下のように変更可能です。

with cupy.cuda.Device(1):
    x_on_gpu1 = cupy.array([1, 2, 3, 4, 5])

CuPyのほとんどの処理はカレントデバイスで行います。カレントデバイスではないデバイス上の配列の処理でエラーが発生するので注意してください。

Chainerは自動でデバイスを切り替え、選ぶいくつかの便利な関数を提供します。例えば、chainer.cuda.to_gpu()関数はnumpy.ndarrayオブジェクトを特定のデバイスへコピーします。

x_cpu = np.ones((5, 4, 3), dtype=np.float32)
x_gpu = cuda.to_gpu(x_cpu, device=1)

これは、以下のCuPyを使ったコードと同じことです。

x_cpu = np.ones((5, 4, 3), dtype=np.float32)
with cupy.cuda.Device(1):
    x_gpu = cupy.array(x_cpu)

GPUデバイス上からCPUへ移動したい場合はchainer.cuda.to_cpu()を用いて以下のようにできます。

x_cpu = cuda.to_cpu(x_gpu)

これは、CuPyを用いて以下のようにするのと同じです。

with x_gpu.device:
    x_cpu = x_gpu.get()
Note

上記のようなwith句は適切なCUDAデバイスを使用するために必要な
ものです。もし、1つのデバイスのみを使用している場合、デバイスを
切り替える必要はありません。

chainer.cuda.to_cpu()とchainer.cuda.to_gpu()関数は自動的に現在の
デバイスを正しく切り替えてくれます。

Chainerはさらにchainer.cuda.get_device()という便利な関数をデバイスを選択するために提供しています。この関数は整数、CuPy配列、NumPy配列またはNone(この場合現在のデバイスを指します)を受け、適切なデバイスオブジェクトを返します。もし引数がNumPy配列の場合、ダミーデバイスオブジェクトが返ります。ダミーデバイスオブジェクトはなにもしないwith句をサポートします。ここにいくつかの例を示します。

cuda.get_device(1).use()
x_gpu1 = cupy.empty((4, 3), dtype='f')  # 'f' indicates float32

with cuda.get_device(1):
    x_gpu1 = cuda.empty((4, 3), dtype='f')

with cuda.get_device(x_gpu1):
    y_gpu1 = x_gpu + 1

このようにNumPy配列を受け取るので、適切なデバイス切り替えをしてくれる関数をNumPyとCuPyともに適用可能なものとして書く事ができます。

def add1(x):
    with cuda.get_device(x):
        return x + 1

CuPyのNumPyとの互換性はCPU/GPU共通コードを書く事を可能にします。これはchainer.cuda.get_array_module()関数により簡単に実現できます。この関数はnumpy、cupyモジュールを引数に応じて返します。CPU/GPU共通関数は以下のように定義できます。

# Stable implementation of log(1 + exp(x))
def softplus(x):
    xp = cuda.get_array_module(x)
    return xp.maximum(0, x) + xp.log1p(xp.exp(-abs(x)))

Single GPUニューラルネットワークを走らせる

Single-GPUの使い方は非常にシンプルです。FunctionSetをGPUへ移して、事前に配列をGPUへ入れておくだけです。このサブセクションでは、ChainerのMNIST exampleのコードを使って話を進めます。

FunctionSetオブジェクトはto_gpu()メソッドを用いて指定されたGPUへ移動できます。GPU版のパラメータと勾配がoptimizerへ渡っているか確認してください。

model = FunctionSet(
    l1 = F.Linear(784, 100),
    l2 = F.Linear(100, 100),
    l3 = F.Linear(100,  10),
).to_gpu()

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

このto_gpu()メソッドはFunctionSet自体を返します。デバイスは指定しなくてもかまいません。その場合はカレントデバイスを使用します。

それから、ミニバッチのすべての計算をGPUへ移しましょう。

batchsize = 100
datasize = len(x_train)
for epoch in range(20):
    print('epoch %d' % epoch)
    indexes = np.random.permutation(datasize)
    for i in range(0, datasize, batchsize):
        x_batch = cuda.to_gpu(x_train[indexes[i : i + batchsize]])
        y_batch = cuda.to_gpu(y_train[indexes[i : i + batchsize]])

        optimizer.zero_grads()
        loss, accuracy = forward(x_batch, y_batch)
        loss.backward()
        optimizer.update()

これはほとんど元々のexampleとおなじコードですが、cuda.to_gpu()関数をミニバッチ配列に挿入しました。

Model-parallel Computation on Multiple GPUs

Data-parallel Computation on Multiple GPUs