Pythonのlist.__mul__

ごさいようじょです。

まずは感じてください。

wandbox.org

これでわかった、とか、知ってるわ、という方は少なくともごさいようじょよりPythonができます。

いま

a = [[]] * 3

[[], [], []]

を作ります。
Pythonicではないとかそういうのは後にしてください。
女児にそういうのを求めるのは野暮というもので、ところで、野暮って言葉の意味知ってますか?

先頭要素の空リストに何かをappendします。

a[0].append(1)

純粋な心を持っているので、ここで

[[1], [], []]

を期待します。

しかし上にあるように実際a

[[1], [1], [1]]

になります。

つまり

[~] * n

で返ってくる

[~, ~, ~]

~の各々は同じ実体、というわけです。

蛇足です。

wandbox.org

さもありなん。

Pythonの「基本は参照」という原則からすると、まあわかりますが気を付けてないとふとした時に踏み抜きます。
(損失は概ね1時間でした)

ここからはもっと蛇足です。

さて、list.__mul__はmethod_wrapperです。
実装は多分これです。

cpython/listobject.c at 3.6 · python/cpython · GitHub

static PyObject *
list_repeat(PyListObject *a, Py_ssize_t n)
{
    Py_ssize_t i, j;
    Py_ssize_t size;
    PyListObject *np;
    PyObject **p, **items;
    PyObject *elem;
    if (n < 0)
        n = 0;
    if (n > 0 && Py_SIZE(a) > PY_SSIZE_T_MAX / n)
        return PyErr_NoMemory();
    size = Py_SIZE(a) * n;github
    if (size == 0)
        return PyList_New(0);

    np = (PyListObject *) PyList_New(size);
    if (np == NULL)
        return NULL;

    items = np->ob_item;
    if (Py_SIZE(a) == 1) {
        elem = a->ob_item[0];
        for (i = 0; i < n; i++) {
            items[i] = elem;
            Py_INCREF(elem);
        }
        return (PyObject *) np;
    }
    p = np->ob_item;
    items = a->ob_item;
    for (i = 0; i < n; i++) {
        for (j = 0; j < Py_SIZE(a); j++) {
            *p = items[j];
            Py_INCREF(*p);
            p++;
        }
    }
    return (PyObject *) np;
}

(これって行番号つかないんですか?)

528, 537行目からが実際のコピー処理です。
elem, pはそれぞれ格納先の各要素(PyObject**), for中のelemが元要素(上の対応では~)です。

ポインタを渡しているので、参照です。(雑理論)

またPy_INCREFでelemの参照カウンタをインクリメントしているのでここからもコピーっぽくないのが感じられます。(雑推論)

つまりそういうことなので、データサイエンティストの皆様におかれましてはPythonのコードはPythonicに書かれることを推奨いたします。

レイバンスパムに引っ掛かったのでサングラスを11個買った

ある日、いつものようにレガシーなクソコードを無限にキレイにしたり、

無限に式テンプレートしてクソコードを無限に高速化したり、もうなんかわからないものをいろいろとジェネリックにする業務を終え、疲弊しながら帰路についた時のことでした。

電車の中でTwitterを眺めていると、有益情報と

クソリプが飛んできました。

急いでFacebookiPhoneアプリから確認しに行きましたが、自分のActivitiesからはよくわかりませんでした。

するとこんなリプライが。

オタクからもこんなSlackが飛んできました。
f:id:tochikuji:20161019000313p:plain

どうやら「レイバンのサングラスが3499円で買えるイベントに参加するのでお前らも参加しろ」といった旨の招待を友達全員に送っていたようです。

今見返すと「昔はTwitterで2499円で売ってたのに、円安の影響かな?」とか思うのですが、その時点ではこの件に関してTwitterでアホみたいに叩かれていた関係もあり、そんな余裕はありませんでした。

(以下、比較的真面目な情報になるので、タイトルだけ回収したい人は下のほうにスクロールしてください)

やったこと

先ずFacebook上でバレずに済む恥は隠滅しようと、当該シェアを取り消そうと思ったのですが、iOSFacebookアプリがクソみたいに使いにくいとかそういうのは別にして、
普段Facebookは特定の友人が自分の写真をアップロードするだけのコンテンツなので全く使い方が分からず、断念しました。
そしてこのへんで事態の収束を図るため、頑張って捕まえた特急を下車し、駅のベンチで慣れないスマートフォンとの格闘を開始しました。

次点に、さらなる被害を防ぐためにFacebook上の怪しいログインセッション、アプリを抹消する作業に移りました。
このへん、iOSFacebook Appがクソでよくわからなかったので共有します。

Facebookアカウントの清浄化

先ず自分のプロフィールから"・・・"アイコンを押して、プライバシーショートカットの設定項目に飛びます。
f:id:tochikuji:20161019002832p:plain

その他の設定からセキュリティ設定に飛び、ログインの場所を開き、怪しい進行中のセッションを抹消しました。
f:id:tochikuji:20161019002947p:plain
瞬殺したのでログはないのですが、発信元IPが大阪のセッションがあったような気がします。

さらに前画面の"設定"から、"アプリ"に飛び"プラットフォーム"から、プラットフォームをOff(他アプリとの連携を許可しない)にして、全ての連携アプリを抹殺しました。
f:id:tochikuji:20161019003529p:plain

さらにレイバンスパム系はどっかのクソザコナメクジサイトから流出したログイン情報を元にパスワードクラックをしている、という話を前々から聞いていたので(この件については後ほど補足します)
"設定"→"一般"→"パスワード"とし、パスワードを秒で変更しました。

加えて、自分の場合ごく少数だったのですが、パスワードが漏れていたらパスワードを共有・類似のパターンのパスワードを使用している他のサービスのアカウントまで引っこ抜かれる可能性があるので、当該サービスのパスワードも秒で変更しました。特にその中に一つ、よく考えるとクレジットカード情報を登録している某サービスがあったのでそちらは神のような速度でアカウントを浄化しました。

Analysis

その後Twitter, Facebook上で火消しを行ってfavとLikeを稼いだあと、鈍行に乗って自宅に戻り、事態の分析に努めました。

Facebook連携

真っ先に疑うのはFacebookの連携アプリです。上述の操作で全て抹消してしまったので、個別の分析は出来ませんが、最初テンパりながらみた時は全く管理していなかったためか、30程はあった気がします。

この辺からも投稿とかShareなどは出来てしまうので皆さんは定期的に連携アプリを確認しましょう。
しかし、ここで先に言ってしまうと、今回の件は十中八九連携アプリによるものではなかった、と考えています。

Activity Logの確認と今回の原因

そのあと、FacebookのWebUIから自分のアカウントのActivity logを確認しました。
この時点ですでに件のイベントはスパムとして削除されており、Activityには招待を送った旨はリストされていなかったのですが、興味深いことを発見しました。
f:id:tochikuji:20161019010138p:plain

下のActivitiesを見ると21:22、スパムShareをするのは21:24ですので、その2分前に複数のアカウントと友達になっていました。
これは「わからんけど多分スパム」ということで放置していたFriend requestsなのですがこれを勝手に承認していたようです。(当然、秒でブロックしました)

こういう手の込んだことをするのか、という感想と共に今回の件の原因もわかってきました。

レイバンスパムの手口について

(ちょっと調べた程度なので間違ったところがあったらウェッブのプロの方ご指摘をお願いします)

Facebookの連携アプリはGraph APIというHTTP(s)ベースのAPIで動作するらしいのですが、このリファレンスを見るとPostやShareをするインターフェースはあっても、Friend requestを承認するたぐいのものは見当たりませんでした。
developers.facebook.com

もっと言えば、ごく狭い範囲の情報の取得以外の操作はFacebookによってアプリの審査を通さないと使えないらしく、既存のサービスがまるごと乗っ取られたのでなければ、スパムアプリにそんな権限が付与されるとは考え難いです。

これらを鑑みて、今回のスパム投稿はFacebookのログイン情報が漏れ、通常のPassword authenticationを通して行われたものであると結論します。

おわび、今後の対策

おそらくパスワードクラックの被害に遭ったと思われる今回の一件について、その原因は「Facebookとか、ろくすっぽ使わんしどうでもええやろ」と7年位変更していない、現行のパスワードの中で最弱の英数字のみで10文字以下のクソザコナメクジパスワードのままずっとFacebookを放置していた私の管理不行き届きにあります。
個人的にはFacebookで殺害予告とかされない限りどうでもいいと思っていたのですが、現行のFacebookのAuth flowにおいてはPassword authenticationは(二段階認証のオプションを除いて)最高権限であり、フレンドの皆さまの情報に直接アクセスできる媒体でした。
事の重大さを捉え、以後このようなことがないよう、アカウントの管理には徹底した注意を払ってゆきます。
スパムShareを飛ばしてしまったフレンドの皆さまに(本当に)深くお詫びします。









それでは本題に入ります。
レイバンサングラススパムに引っ掛かったので、サングラスを11個買いました。
本当はもっとたくさん買ってTwitterにアップしたかったのですが、これしかなかったので、とりあえずあるだけ買い占めてきました。
f:id:tochikuji:20161019214751j:plain

先に述べたようにこの度は各方面に多大なご迷惑をお掛けしました。
その中には私のシェアをみてサングラスに対する購買意欲を刺激されてしまった方も多分にいらっしゃることでしょう。
ひいてはこの度私が陳謝の意を込めて、そういった方に無料にてサングラスを進呈いたします。

この度被害に遭われた方、あるいは関係ないけどこの記事を読んだ方は、ご連絡をいただければ今度私とお会いした時にサングラスを差し上げます。(今限り、11個限定)
Facebook, Twitter, 電凸等媒体は問いません。
上記の写真よりご所望のモデルを指定の上、ご連絡ください。

また、更なるお詫びの印として5年くらい変えてなかったFacebookのプロフィール写真を変更しました。
フレンドの方はご査収ください。

以上になります。長文失礼しました。

chainerでStacked denoising Autoencoder

イマドキのナウいようじょなのでもっぱらNeural networkで遊んでます.

Autoencoder(自己符号化器)の話をします.
Autoencoder、というよりNeural Net一般の問題でありますが、ネットワークの構造を深くしてゆくと逆伝搬の途中でその勾配が弱まっていってしまって, NNの前段と後段で逆伝搬される勾配が異なってくる勾配消失(Gradient vanishing)という現象が大きな問題となってきます. このへんは青い本に書いてあった気がするのですが高くて買ってないですし、あんまり詳しくないので詳しくは述べません.

 そのため深いAutoencoderを構成する際には段ごとにその前段からの入力を元に戻すように学習させ、そうして一層ずつ学習させたネットワークを積み上げる(stack)という技法が用いられ、そうして構成されたAutoencoderをStacked Autoencoderといいます.イメージとしては(面倒なので図は用意しません)
1. 入力 x -> [AE 1層目] -> [AE 1層目をひっくり返したもの] -> x となるように学習
2. 入力 x -> [AE 1層目(固定)] -> [AE 2層目] -> [AE 2層目.T] -> x
3. 入力 x -> [AE 1層目(固定)] -> [AE 2層目(固定)] -> [AE 3層目] -> [AE 3層目.T] -> x
4~n. 以下同様 といった感じです.

そんな感じの学習を行うプログラムを書いてみました.もちろんchainerで.

Stacked denoising(deep) Autoencoder 安直に小さいネットワーク作ってやってますが、もっと賢い書き方あるかもしれませんね.
まあきちんと書いてないのもありますが、わかりにくいですし長いです.もっと楽にかけたらいいんですけどね……

f:id:tochikuji:20150916210438p:plain

ん…?

f:id:tochikuji:20150916210916p:plain

あっ!!

ということでStacked Autoencoderを拙作libDNNに実装しました. (過去記事参照) 

tochikuji.hatenablog.jp

以下MNISTを3層のAutoencoderで学習させるサンプルです.

Stacked denoising(deep) Autoencoder (with libDNN)

通常のAutoEncoderと同様に大きなモデルも一気に定義してしまって,その積み上げ順と多少のお作法に則ったencoding, decodingの伝搬規則を書けば後はtrain一発で通るようにしてあります. めっちゃ便利ですね.
手がまわなくて未だドキュメントとExampleのコメントを書いてないので身体で感じてください.(あるいは誰か書いてください)
ドキュメントきちんと書きました。pushしてなかっただけです。