shutil.copyfileでpermission deniedがでたときは引数を見直そう[Python][shutil]

Windowsでファイルをあるフォルダへコピーするコードを書いた際,以下のエラーがでた.

import shutil

path1 = r"C:\Users\hoge\Documents\hoge\hoge.pdf"
path2 = r"C:\Users\hoge\Documents\hoge2"

shutil.copyfile(path1, path2)
>>
PermissionError: [Errno 13] Permission denied: 'C:\Users\hoge\Documents\hoge2'

このエラーを見たとき,hoge2というフォルダにアクセス権限が無いのかと勘違いし,管理者権限でコマンドプロンプトを開いたり,フォルダの読み取り設定を見直したりした.

しかし,エラーの原因はフォルダにアクセス権限が無いことではないのだ.

実は,shutil.copyfileは引数として入力ファイル名・出力ファイル名を与えなければならない関数だったのだ.

11.10. shutil — 高水準のファイル操作 — Python 3.6.5 ドキュメント

この為,エラーは引数として与えたものが出力フォルダ名だったことが原因だ.

そして,ファイルをあるフォルダへコピーする際にはshutil.copyを使うべきだったのだ.

import shutil

path1 = r"C:\Users\hoge\Documents\hoge\hoge.pdf"
path2 = r"C:\Users\hoge\Documents\hoge2"

shutil.copy(path1, path2)

なんという凡ミス.しかしながら,Permission deniedとエラーがでるのはちと混乱を招く気がする.

機械学習キワモノデータセット集[ML][Dataset]

機械学習をやってると,MNISTやCIFARなどの真面目ーなデータセットでは無く,おもしろくて刺激的なデータセットで結果を見てみたいなと思いません?

本記事ではそんなあなたの為に筆者が見つけたキワモノデータを紹介.


ナイフが映った画像のデータセット キワモノ度:☆

f:id:Vastee:20181012170618p:plain

*1

監視カメラの動画からナイフが映った画像をキャプチャして作ったデータセット.ナイフというと刺激的な気がするが,防犯目的のようなので真面目?

ナイフが映っている画像は3,559件,ナイフが映っていない画像は9,340件ある.CNNの2値分類を試す際にすぐ使えそう.

Download link: http://kt.agh.edu.pl/~matiolanski/KnivesImagesDatabase/


様々な種類のグラフ画像のデータセット キワモノ度: ☆☆

f:id:Vastee:20181013114423p:plain

*2

棒グラフ,横棒グラフ,線のグラフプロット,ドットのグラフプロット,円グラフの画像が大量に収録されたデータセット

グラフ画像のデータセットを作った目的としては,グラフ画像から自動で数値を読み取る人工知能を作る為である.こんなもの作って何の役に立つの?と思われるかもしれないが,世間では高いニーズがある.なぜなら,PDF形式などでまとめられた非構造データである特許文書や科学技術論文にはグラフ画像が大量にある為,自動で数値を読み取る人工知能があると眠っていたデータが大量に獲得できるのである.文献から獲得できる大量のデータはまさに人類の英知そのもの.このように文献から獲得できるデータはとても貴重なのでデータサイエンティストによっては喉から手が出るほど欲しいデータだというわけである.

このデータセットを作成したのは,トロント発のAIスタートアップ"Maluuba"である.ちなみにMaluubaは2017年に米マイクロソフトに買収された.

Download link: https://datasets.maluuba.com/FigureQA


ドン勝プレイヤーを予測する為のデータセット キワモノ度:☆☆☆

f:id:Vastee:20181013120055p:plain

*3

大人気ゲームPUBGのデータセット.PUBGは100人のプレイヤーが最後の一人になるまで戦うバトルロワイヤル形式のゲームである.そして,本データセットでは,説明変数として,キル数・キルした場所・回復した回数・ 乗り物を破壊した回数など,ゲームに関するあらゆるパラメータが提供され,目的変数として,プレイヤーの最終順位が提供されている.また,データ形式csvである為,比較的扱いやすい.

データ解析のついでにドン勝の仕方もわかる(?)面白いデータセットだ.

Download link: https://www.kaggle.com/c/pubg-finish-placement-prediction/data


食物連鎖に関する画像と質問応答のデータセット キワモノ度:☆☆☆☆

f:id:Vastee:20181012172400p:plain

*4

子供向けの生物の教科書にある食物連鎖に関する図とその質問応答が収録されたデータセット.扱うテーマは面白いが,画像がダイアグラム形式で書かれているので,単純な画像認識ではそもそも情報抽出が行えない.つまり,とても扱いにくいデータセットである.

このデータセットを作成したのはマイクロソフトの共同創業者のPaul Allenが設立したAllen Instituteという非営利の独立型研究所だ.食物連鎖の図をターゲットにするという発想のぶっ飛び具合と,それを解析する卓越した技術力には頭が上がらない.

紹介するデータセットの内,マイクロソフト関連が2件もあるとは何たる偶然.

Download link: https://allenai.org/paper-appendix/emnlp2016-p3/


女子高校生の100m疾走後の感想文データセット キワモノ度:☆☆☆☆☆

栄えあるキワモノ度第1位のデータセットは,なんと日本発のものだ.

内容はタイトル通りで説明することは無い.言っておくが本データは趣味では無く教育目的で作成されたものである.

誠に残念なことにデータセットは非公開だ.しかし,論文はあるので暇な人は見てみると良い.

Paper link: ci.nii.ac.jp

タイトルだけでキワモノだということが分かると思う.

*1:画像は,論文"CCTV object detection with fuzzy classification and image enhancement"(https://link.springer.com/content/pdf/10.1007%2Fs11042-015-2697-z.pdf)より転載

*2:画像は,https://datasets.maluuba.com/FigureQAより引用

*3:画像は,https://www.kaggle.com/c/pubg-finish-placement-prediction/dataより転載

*4:画像は,論文"Semantic Parsing to Probabilistic Programs for Situated Question Answering"(http://www.aclweb.org/anthology/D16-1016)より転載

Pytorch v0.4のコードをv0.3で動かす際には.dataに注意!![Pytorch]

Pytorchのコードを見ているとミニバッチごとのlossやaccuracyを計算する際、.dataを用いて値を取り出されることが頻繁にある。

よくある例:

for i in range(0, 2 * POS_NEG_SAMPLES, BATCH_SIZE):
      inp, target = dis_inp[i:i + BATCH_SIZE], dis_target[i:i + BATCH_SIZE]
      dis_opt.zero_grad()
      out = discriminator.batchClassify(inp)
      loss_fn = nn.BCELoss()
      loss = loss_fn(out, target)
      loss.backward()
      dis_opt.step()

      total_loss += loss.data # .dataを使ってlossから値を取り出しtotal_lossに蓄積
      total_acc += torch.sum((out>0.5)==(target>0.5)).data # .dataを使ってaccuracyを取り出しtotal_accに蓄積

.dataを用いて値を取り出す上のコードは、pytorch v0.4で動かすならエラーがでない。

しかし、上のコードをpytorch v0.3で動かすと下のエラーが発生する。

# pytorch v0.3で動かした際のエラー

TypeError: div_ received an invalid combination of arguments - got (float), but expected one of:
 * (int value)
      didn't match because some of the arguments have invalid types: (!float!)
 * (torch.cuda.ByteTensor other)
      didn't match because some of the arguments have invalid types: (!float!)

なぜv0.4で動いていたコードがv0.3で動かなくなってしまうのか?

その原因は、pytorch v0.3でVariableの型の行列から値を取り出す際に.dataを使用するとデータの型がVariableからTensorに変わってしまうからである。

簡単な例で問題をみていこう。

# Pytorch v0.4で動かすと問題ないのだが、v0.3で動かすとエラーが発生するコード
# 本コードではv0.3で動かしたことを想定

import torch
from torch.autograd import Variable

x = Variable(torch.Tensor([1,2,3])) # ListからTensorに変換し、更にTensorをVariableに変換

y = Variable(torch.Tensor([4,5,6])).data # .dataを使ってVariableから値を取り出す。

# 返り値を表示。xにはVariableが格納されていることがわかる。
x
>>
Variable containing:
 1
 2
 3
[torch.FloatTensor of size 3]

# 返り値を表示。yはVariableではなくTensorが格納されてしまった。
y
>>

 4
 5
 6
[torch.FloatTensor of size 3]

# TensorとVariableを加算するとエラーが発生
x+y
>>
Traceback (most recent call last):

  File "<ipython-input-188-259706549f3d>", line 1, in <module>
    x+y

RuntimeError: add() received an invalid combination of arguments - got (torch.FloatTensor), but expected one of:
 * (float other, float alpha)
 * (Variable other, float alpha)

上の例のようにpytorch v0.3では、.dataで値を取り出すと型違いによるエラーが発生してしまう為、v0.4で動いていたコードが動かなくなる。

v0.4ではVariableとTensorが統合された為、型違いによるエラーが発生しないようだ。

v0.4公式がまとめた変更点(英語)

pytorch.org

v0.4の変更点が日本語でまとめられた記事

qiita.com

ちなみに、v0.4の公式ドキュメントでは.dataを使うことはunsafeだと言っており、代わりに.detachを使うことが推奨されている。

pytorch.org

What about .data ? のセクションに .dataを使うことの危険性が述べられている。

.dataで値を取り出した場合、xに対する変更がautogradで追跡できない為、危険視されているようだ。

最後に.detachを使用して書いた、v0.3とv0.4ともにエラーが発生しないコードを載せる。

# v0.3とv0.4ともにエラーが発生しないコード
import torch
from torch.autograd import Variable

x = Variable(torch.Tensor([1,2,3])) # ListからTensorに変換し、更にTensorをVariableに変換

z = Variable(torch.Tensor([7,8,9])).detach()

z
>>
Variable containing:
 7
 8
 9
[torch.FloatTensor of size 3]

# v0.3とv0.4ともにエラー無しで加算が行える
x+z
>>
Variable containing:
  8
 10
 12
[torch.FloatTensor of size 3]

追記

あまり良い方法ではないのだが、lossやaccuracyなど1x1の値を取り出す場合には、.data[0]を使う手もある。

.data[0]は、下のIrfan_Buluさんの回答を見て知った。

discuss.pytorch.org

pythonでグラフデータベースを構築[Python][GraphDataBase][Neo4j]

f:id:Vastee:20180509140835g:plain

本記事では、グラフデータベースNeo4jを用いて、簡単なグラフをpythonで記述する方法を紹介。

まずはNeo4jのインストールから済ませよう

vastee.hatenablog.com

Neo4jのインストールが終わったら、Neo4jのpythonラッパーneo4jrestclientをインストール

pip install neo4jrestclient

これで準備完了。

では、pythonでグラフを描いてみよう。

from neo4jrestclient.client import GraphDatabase

url = "http://127.0.0.1:7474/db/data/" #http://localhost:...と記述すると認識してもらえなかった

gdb = GraphDatabase(url) #ここでエラーが出る場合はsudo pythonを試してみよう

gdb.query("MATCH (n) OPTIONAL MATCH (n)-[r]-() DELETE n,r", data_contents=True)

alice = gdb.nodes.create(name="Alice", age=30)
bob   = gdb.nodes.create(name="Bob", age=30)
ken   = gdb.nodes.create(name="Ken", age=35)

alice.labels.add("Person")
bob.labels.add("Person")
ken.labels.add("Person")

bob.relationships.create("Knows", alice, since=1980)
alice.relationships.create("Knows", bob, since=1983)
alice.relationships.create("Knows", ken, since=2015)

上のプログラムは実行しても何の反応も無い。

グラフを見る為にはWebアプリを使わなければならない。

FirefoxなどのWebブラウザのURL欄に http://localhost:7474/browser/ を打ち込もう。

そしてでてきたUIのコマンド入力欄に

MATCH (n)-[r]-(m) RETURN n, r, m

と打てば、スクリプトで作成したグラフが表示される。

f:id:Vastee:20181001170230p:plain

以上。

フォルダ内のファイルを階層ごとに表示するtreeコマンドの紹介[Windows]

階層表示したいフォルダでShift+右クリックし,PowerShellウィンドウをここに開くをクリック.

 

以下のtreeコマンドに引数/fをつけて入力

 

tree /f

 

C:.
└─data
├─test
│ ├─0
│ │ train_0000010.tif
│ │ train_0000011.tif
│ │ train_0000012.tif
│ │ train_0000013.tif
│ │ train_0000014.tif
│ │
│ └─1
│ train_0000015.tif
│ train_0000016.tif
│ train_0000017.tif
│ train_0000018.tif
│ train_0000019.tif
│
└─train
├─0
│ train_0000005.tif
│ train_0000006.tif
│ train_0000007.tif
│ train_0000008.tif
│ train_0000009.tif
│
└─1
train_0000000.tif
train_0000001.tif
train_0000002.tif
train_0000003.tif
train_0000004.tif

 

treeコマンドは普段使うことは無い.

 

だが手順書などにフォルダ構成を載せるときに使うので,メモ.

別々のフォルダに散らばって保存されたファイルを1つにまとめる[Python]

└─data
    ├─test
    │  ├─0
    │  │      train_0000010.tif
    │  │      train_0000011.tif
    │  │      train_0000012.tif
    │  │      train_0000013.tif
    │  │      train_0000014.tif
    │  │
    │  └─1
    │          train_0000015.tif
    │          train_0000016.tif
    │          train_0000017.tif
    │          train_0000018.tif
    │          train_0000019.tif
    │
    └─train
        ├─0
        │      train_0000005.tif
        │      train_0000006.tif
        │      train_0000007.tif
        │      train_0000008.tif
        │      train_0000009.tif
        │
        └─1
                train_0000000.tif
                train_0000001.tif
                train_0000002.tif
                train_0000003.tif
                train_0000004.tif

こういった様々なフォルダに散らばって保管されたファイルたちを一つのフォルダにまとめるスクリプトを紹介.

import os
import shutil
from glob import glob

files = "data/*/*/*.tif"
dst = "path/to/dst"

for file in glob(files):
    dst_file_path = os.path.join(dst, os.path.basename(file))
    shutil.copy(file, dst)

globを使って2階層以上のファイルをリスト化したことが工夫点

もし良かったら使ってください.