画像認識と小説スノウ・クラッシュ

図書館でニュートンを立ち読みしてたら、人工知能の特集をやってて、何となくパラパラめくってたら、AIの弱点みたいなページがあった。どう見てもパンダの画像なのに、細工を施したノイズを混ぜることでテナガザルと認識させられるとかいう内容。

ainow.aitogetter.com

それで思い出したのだが、今から25年前に書かれた『スノウ・クラッシュ』っていうSF小説に似たような話が出てくる。VRの世界(今で言うMMORPGみたいなものか?)で、人間に特殊なノイズというかビットマップを見せることで人間の脳みそをクラッシュさせたり操ったりできるとかいう内容。当時も人工知能は流行ってたんだっけ? 確かエキスパートシステムとか何とか世代コンピュータとか聞いたことがある。それから人工知能研究は冬の時代に入り、また最近になって盛り返してきてるわけだ。

もし人間の意識を全てニューラルネットワークで説明できるなら、視覚に依存した生命にも似たような脆弱性があるんじゃないかとふと思ったけど、それはないか。何億年にも渡って進化してきた生命に、そんなわかりやすい脆弱性が残ってるわけがないというか、もしあったとしても錯視ぐらいなものかな。うん。

objectとtypeの関係を図にまとめた

なお、図では以下のようなクラスを使いました。

# 何も継承指定しないとobjectを継承したことになる(※Python3から)
class Foo: pass
# Fooを継承
class Bar(Foo): pass

# 独自のメタクラスを作成して使用
class MyType(type): pass
class Hoge(metaclass=MyType): pass

# クラスのインスタンス化
f = Foo()
b = Bar()
h = Hoge()

# ビルトインタイプのインスタンス化
n = 123
s = 'hello'

object

クラスの継承元を辿っていくと必ずobjectにたどり着きます。

f:id:itasuke:20171210224844p:plain

# 再掲
class Foo: pass
class Bar(Foo): pass

# ごく普通の継承
print(Foo.__bases__[0] is object)  # True
print(Bar.__bases__[0].__bases__[0] is object)  # True !!

# ビルトインタイプも同様
print(int.__bases__[0] is object)  # True
print(str.__bases__[0] is object)  # True

なぜ __bases__[0] のように複数形なのかというと、多重継承できるからです。

type

Pythonではクラスも含め全てがオブジェクトということになっています。では「そのオブジェクトはどのクラスから作られたの?」という質問を繰り返すと必ずtypeに辿り着きます。

f:id:itasuke:20171210224841p:plain

# 再掲
n = 123
s = 'hello'
f = Foo()
b = Bar()
h = Hoge()

# あなたのクラスは...?
print(n.__class__ is int)  # True
print(s.__class__ is str)  # True
print(f.__class__ is Foo)  # True
print(b.__class__ is Bar)  # True
print(h.__class__ is Hoge)  # True

# あなたのクラスのクラスは...?
print(n.__class__.__class__ is type)  # True
print(s.__class__.__class__ is type)  # True
print(f.__class__.__class__ is type)  # True
print(b.__class__.__class__ is type)  # True
print(h.__class__.__class__ is MyType)  # True !!
print(h.__class__.__class__.__class__ is type)  # True !!

issubclass / isinstance という関数もあるけれど

実は issubclassisinstance 関数を使うと、継承関係を一発で調べることができます。

print(issubclass(Bar, Foo))  # True
print(issubclass(Bar, object))  # True

print(isinstance(b, Bar))  # True
print(isinstance(b, Foo))  # True
print(isinstance(Bar, type))  # True
print(isinstance(Hoge, MyType))  #True !!

一方で、これらの関数は実際の継承関係になくても、継承していることにしてしまうことがあるので、この記事では使いませんでした。

from collections.abc import Sequence

print(issubclass(str, Sequence))  # True !!
print(isinstance('hello', Sequence))  # True !!

# str は Sequence なんぞ継承しとらんぞ
print(str.__mro__)  # (<class 'str'>, <class 'object'>)

なぜこんな機能が必要かというと、↓このような型チェックのために使います。ダックタイピングってやつです。

import collections.abc

# 何も継承しない(objectは除く)
class ZZZ:
    def __len__(self):
        return 0

def print_length(obj):
    # 抽象基底クラスの確認
    if isinstance(obj, collections.abc.Sized):
        print('あなたの長さは %d です' % len(obj))
    else:
        print('あなたに長さはありません')

# 長さのあるオブジェクト達
print_length('hello')  # 5
print_length([1, 2, 3])  # 3
print_length({'A':'ei', 'B':'bee'})  # 2
print_length(ZZZ())  # 0

# 長さのないオブジェクト達
print_length(None)  # なし
print_length(open)  # なし
print_length(123)  # なし

以上です。

PowerShellとファイルの日付についてちょっとしたこと

PowerShellを使うとファイルやフォルダーの日付を簡単に変更できますが、

(Get-Item c.txt).LastWriteTime = '2012/3/4 5:6:7'

ちゃんと小数点以下まで指定しないと、日付を変更したことがばれます。

Get-Item *.txt | Select-Object Name,{$_.LastWriteTime.ToString('yyyy/MM/dd HH:mm:ss.fffffff')}

f:id:itasuke:20171214160136p:plain

少し前に、証拠データの日付を書き換えた検察官がいて問題になったことがあります。遠隔操作ウイルス事件もそうですが、日本ではあまりフォレンジックとかやらないんでしょうか。

どれくらい昔の日付に設定できる?

ウィキペディア調べるとNTFSはファイルの日付を1601年1月1日 0時0分0秒 (UTC) から100ナノ秒単位で保持しているようです。論理的にはこの日付に設定できるはずですが、実際にやってみるとできません。

(Get-Item c.txt).LastWriteTimeUtc = '1601/1/1'

これはWindowsAPIの仕様で、SetFileTime関数に基点となる日付からきっかり 0 秒後が指定されるとスルーされてしまうのです *1。そういうわけで、0時0分0.0000001秒が、設定できる最も古い日付ということになります。

(Get-Item c.txt).LastWriteTimeUtc = '1601/1/1 0:0:0.0000001'

f:id:itasuke:20171214160127p:plain

ところで、C言語のFILETIME構造体と.NETのDateTime構造体は少し仕様が違います。分解能は同じですが、後者は基点が西暦1年になっています *2。なので、PowerShell側で以下のような日付を作ることは可能ですが、

$dt = [datetime] '0001/1/1'

この日付をNTFSのファイルに指定するとWin32エラーになるのはそういう理由です。

(Get-Item c.txt).LastWriteTimeUtc = $dt
# "LastWriteTimeUtc" の設定中に例外が発生しました:
# "有効な Win32 FileTime ではありません。"

以上です。

*1:そもそもPowerShellはSetFileTime関数を使っているのかという疑問がありますが、少なくとも Process Monitor で見る限り呼び出しているようです。また、FILETIME構造体も日付の仕様はNTFSと同じです。

*2:http://referencesource.microsoft.com/#mscorlib/system/datetime.cs,131 コメントより

EvernoteClipper.exeの常駐設定

Evernoteのクライアントをインストールすると、EvernoteClipper.exeが常駐するようになる。自動起動から外しておいても、Evernoteのクライアントと一緒に起動してきて、クライアント終了後に常駐する。

自分はウェブをクリップする時、この機能は使わず、範囲選択してからコピー&ペーストしている。EvernoteClipper.exeを起動させておくと、極わずかだがメモリとCPUサイクルを余計に消費するので、以前は icacls でアクセス許可を変更し実行拒否にしていた。(ファイルの削除で対処すると、インストーラーが起動してきて元に戻そうとする)

icacls EvernoteClipper.exe /deny "everyone:(x)"

しかし、アップデートごとにこれを実行するのは面倒くさくて、しばらく放置していたのだが、今日ふと検索してみると、レジストリーに起動させなくなるオプションがあるのね。

discussion.evernote.com

Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Evernote\Evernote]
"StartEvernoteClipper"=dword:00000000

f:id:itasuke:20171213123722p:plain

これで起動しなくなったっぽい。

マイナスはリテラルの一部じゃなくて演算子

二乗したのに符号がマイナスなんだけど「こいつ虚数か?」と思ったら、単純に ** が先に評価されているだけでした。

>>> -1 ** 2
-1
>>> (-1) ** 2
1

よく読むと、チュートリアルにも記載されてるし。

- よりも ** の方が優先度が高いので、-3**2-(3**2) として解釈され、結果は -9 になる。こういうふうに解釈されないよう (-3)**2 にすると 9 という結果が得られる。

Since ** has higher precedence than -, -3**2 will be interpreted as -(3**2) and thus result in -9. To avoid this and get 9, you can use (-3)**2.

https://docs.python.org/3/tutorial/introduction.html#id3

きっとあまりにも間違える人が多いので、わざわざ注意書きしてあるんでしょうね。なんかすいません。

そもそも - ってリテラルの一部じゃなくて演算子なのね。-1 を ast で分解させるとこの通り。

>>> import ast
>>> ast.dump(ast.parse('-1'))
'Module(body=[Expr(value=UnaryOp(op=USub(), operand=Num(n=1)))])'

つまり、こういうことです。

class SmileParty:
    def __neg__(self):
        return 'ネガティブから'
    def __pos__(self):
        return 'ポジティブに'

s = SmileParty()
print(-s)
print(+s)
print('切り替える')

www.youtube.com