Githubのトレンドを取得するGithub Unofficial Trending API
はじめに
GithubのTrendingをコードから取得したいと思いAPIがないか探した。 Github API v4のドキュメントでtrendingがつくものを探していたが見つからなかった。 他でも探していると、 stackoverflowでの回答や、 Githubのコミュニティフォーラム に公式のAPIはないようなことが書かれていた。 そこで、非公式のもので、Trendingを取得できるものを見つけたので、それを使ってみようと思う。
Github Unofficial Trending API
Github のAPIで不足しているTrendingを取得できる非公式API
- リポジトリ: https://github.com/huchenme/github-trending-api
- リファレンス : https://githubtrendingapi.docs.apiary.io/#
ブラウザで試してみる
試しに、ブラウザにhttps://ghapi.huchen.dev/repositories?language=javascript&since=weeklyを入力すると、結果が表示される。
これは、言語がjavascript
で期間がweekly
つまり一週間のトレンドを取得するものである。
json形式の結果が得られる。下が結果の一部で、リポジトリ名を確認してみると
1番目は、project_corona_tracker
で、
2番目がdecentralized-video-chart
ということがわかる。
[ { "author": "adrianhajdin", "name": "project_corona_tracker", "avatar": "https://github.com/adrianhajdin.png", "url": "https://github.com/adrianhajdin/project_corona_tracker", "description": "This is a code repository for the corresponding YouTube video. In this tutorial we are going to build and deploy a corona tracker application. Covered topics: React.js, Chart.js, Material UI and much more.", "language": "JavaScript", "languageColor": "#f1e05a", "stars": 341, "forks": 89, "currentPeriodStars": 178, "builtBy": [ { "username": "adrianhajdin", "href": "https://github.com/adrianhajdin", "avatar": "https://avatars3.githubusercontent.com/u/24898559" } ] }, { "author": "ianramzy", "name": "decentralized-video-chat", "avatar": "https://github.com/ianramzy.png", "url": "https://github.com/ianramzy/decentralized-video-chat", "description": "🚀 Zipcall.io 🚀 Peer to peer browser video calling platform with unmatched video quality and latency.", "language": "JavaScript", "languageColor": "#f1e05a", "stars": 1945, "forks": 183,
これをGithubのTrendingのページで確認してみる。上の結果と同じで、
きちんと、言語がjavascript
、期間がweekly
のtrendingを取得できていることがわかる。
使い方
Trendingは
- Repositories (リポジトリ)
- Developers (開発者)
がある。
リポジトリのトレンドを取得
ベースとなるurl
https://ghapi.huchen.dev/repositories
にパラメータを足していく。パラメータを足すときは、urlの後ろに?
をつけて、parameter名=値
という形で追加していく。複数あるときは、&
でつなぐ。
パラメータ名 | 説明 |
---|---|
language | プログラミング言語(e.g. javascript ,python ,c%23 (c#) など) |
since | 期間 (daily ,weekly ,monthly から選ぶ。) |
spoken_language_code | 話す言語(ja ,en など) |
language
: https://github.com/huchenme/github-trending-api/blob/master/src/languages.json
spoken_language_code
: https://github.com/huchenme/github-trending-api/blob/master/src/spoken-languages.json
にあるurlParam
の値。
例
https://ghapi.huchen.dev/repositories?since=daily&spoken_language_code=ja
結果はリスト形式で得られる。そのリストの個別のオブジェクトは下のようになっている。
{ "author": "リポジトリのオーナ", "name": "リポジトリ名", "avatar": "アバターのurl", "url": "リポジトリurl", "description": "リポジトリ説明", "language": "プログラミング言語", "languageColor": "githubのプログラミング言語の色", "stars": スター数, "forks": フォーク数, "currentPeriodStars": 期間内についたスター数, "builtBy": [ { "username": "ユーザー名", "href": "ユーザーurl", "avatar": "アバターurl" }, { "username": "ユーザー名", "href": "ユーザーurl", "avatar": "アバターurl" } ] }
開発者のトレンドを取得
ベースとなるurl
https://ghapi.huchen.dev/developers
パラメータ名 | 説明 |
---|---|
language | プログラミング言語(e.g. javascript ,python ,c%23 (c#) など) |
since | 期間 (daily ,weekly ,monthly から選ぶ。) |
例
https://ghapi.huchen.dev/developers?language=javascript&since=daily
結果はリスト形式で得られる。そのリストの個別のオブジェクトは下のようになっている。
{ "username": "ユーザー名", "name": "変更できる名前", "url": "ユーザーurl", "avatar": "アバターurl", "repo": { "name": "人気のリポジトリ名", "description": "リポジトリ説明", "url": "リポジトリのurl" } }
pythonで実行
import urllib.request import json endpoint_repo="https://ghapi.huchen.dev/repositories" endpoint_developer="https://ghapi.huchen.dev/developers" def get_trending_repositories(language=None,\ since="daily",spoken_language_code=None): params="" params+="?since="+since if language is not None: params+=("&language="+language) if spoken_language_code is not None: params+=("&spoken_language_code="+spoken_language_code) url=endpoint_repo+params with urllib.request.urlopen(url) as res: body=res.read() j=json.loads(body) return j def get_trending_developers(language=None,since="daily"): params="" params+="?since="+since if language is not None: params+=("&language="+language) url=endpoint_developer+params with urllib.request.urlopen(url) as res: body=res.read() j=json.loads(body) return j
レポジトリのtrendingを取得してみる。期間:今日、話し言語は:日本語、プログラミング言語:pythonで実行してみた。
def show_trending_repos(since="daily",language=None,spoken_language_code=None): result=get_trending_repositories(since=since,language=language,\ spoken_language_code=spoken_language_code) for i,repo in enumerate(result): print(i,"番目") print("リポジトリ名:",repo["name"]) print("url:",repo["url"]) print() with open("test.json","w",encoding="utf-8") as f: json.dump(repo,f,indent=4) if __name__=="__main__": show_trending_repos(since="monthly",language="python",\ spoken_language_code="ja")
結果は下のようになった。trendingと一致している。trendingの数は、25個などの時もあれば、0個や1個の時もある。
0 番目 リポジトリ名: deep-learning-from-scratch url: https://github.com/oreilly-japan/deep-learning-from-scratch
開発者のtrendingも試した。
def show_trending_developers(since="daily",language=None): result=get_trending_developers(since=since,language=language) for i,developer in enumerate(result): print(i,"番目") print("ユーザー名:",developer["username"]) print() with open("test.json","w",encoding="utf-8") as f: json.dump(developer,f,indent=4) if __name__=="__main__": show_trending_developers(since="daily",language="javascript")
結果は25個あったので省略。 きちんと現在のtrendingと同じであった。
まとめ
Github の公式APIには、Trendingを取得するものがなかった。 そこで、非公式のTrendingを取得するAPI、Github Unofficial Trending APIを使ってTrendingを取得してみた。 使い方も簡単で、きちんと動作していた。
Github API v4を使ってみる(1)動かしてみる
はじめに
Githubの情報(リポジトリやスター数など)をコードから取得できる、Github APIがある。 Github APIのバージョンにはv3とv4がある。v3はREST APIで、v4はGraphQLというものをベースにしたAPIとなっている。
GraphQLベースのv4を2種類の方法で使ってみる。
使ってみる
使い方としては、2つの方法があり、
- GraphQL Explorer
- アクセストークンを使う方法
を使うことで、APIを呼び出す。GraphQL Explorerは、ブラウザーで使えて、入力補完もしてくれるので使いやすい。
1. GraphQL Explorerを使う方法
GraphQL Explorerは、 Github APIをブラウザーで使えるようにしたもの。 GraphiQLをベースにしてある。 GraphQL Explorerは、queryのみ使え、読み込みのみ出来る。
まず、https://developer.github.com/v4/explorer/ でGraphQL Explorerのページを開く。
右上のsign inでgithubにサインインする。
権限の許可のページが出てくる。 権限は、下のものへのアクセスの許可が求められている。
user public_repo repo repo_deployment repo:status read:repo_hook read:org read:public_key read:gpg_key
緑のAuthorize githubと書いてあるボタンを押して、許可する。
explorerのページへ飛び、explorerが使えるようになる。これで、github apiを使うことが出来る。
最初に書かれているクエリで試してみる。
query { viewer { login } }
丸い実行ボタンを押すことで、実行される。
結果は右側の部分に表示される。
{ "data": { "viewer": { "login": "3sdd" } } }
これで、explorerを使ってGithub APIを使えるようになった。 jsonファイルにしたければ、適当なファイル名(data.jsonなど)を付けて、結果を保存する。
GraphiQLでも、設定することで使うことができるようである。
https://developer.github.com/v4/guides/using-the-explorer/#using-graphiql
2. アクセストークンを使う方法
アクセストークンを使って、リクエストで取得することもできる。
githubのガイドではcurlが使われていた。 今回は、pythonで試してみる。
コマンドで使うには、アクセストークン(personal access token)が必要となる。 githubでアクセストークンを作る。 このページにアクセストークンの 作り方が書いてある。画像の通り進めていく。 スコープについての設定は、上のexplorerと同様のものにしておく。
user public_repo repo repo_deployment repo:status read:repo_hook read:org read:public_key read:gpg_key
作成すると、下の画像のように黒塗りの部分にアクセストークンが生成されるので、保存しておく。
次にアクセストークンを使って、Github APIを呼び出す。
今回は、pythonのバージョンは3.7.4で実行した。
先ほど、作ったアクセストークンをヘッダーにセットしてプログラムからアクセスできるようにする。valuesの値部分のquery{...}
の部分は求めたいクエリにする。今回は、ログイン者の情報を求める。
import urllib.request import json personal_access_token="アクセストークン記入" # 自分のアクセストークン endpoint="https://api.github.com/graphql" #送信先のendpoint headers={"Authorization":f"Bearer {personal_access_token}"} values={"query":"query{viewer{login}}"} # query部分 値に内容を書く data=json.dumps(values) #strにする data=data.encode("utf-8") #byte型へ変換する #リクエストを作成送信して、結果を得る。 req=urllib.request.Request(endpoint,headers=headers,data=data) with urllib.request.urlopen(req) as response: body=response.read() #結果が変数bodyに入っているのでjson形式で整形して # data.jsonというファイルを作成し保存する j=json.loads(body) with open("data.json","w",encoding="utf-8") as f: json.dump(j,f,indent=4)
実行してみると、
data.json
というファイルが出来て、
中にはクエリで求めた情報、
ログインユーザーの情報が入っている。
{ "data": { "viewer": { "login": "3sdd" } } }
おわりに
Github API v4をGraphQL Explorerとアクセストークンを使う2種類の方法で試してみた。 GraphQL Explorerは、補完もあり手軽に試せる。プログラムから使いたいときは、アクセストークンを作って使うことが出来る。
次は、クエリの内容について調べたい。
参考サイト
PyTorchでの学習の進み具合をプログレスバーで表示してみる
はじめに
前回、tqdmを使って、プログレスバーを表示してみた。
今回は、実際にpytorchを使って、ニューラルネットワークを学習する時の学習の進行度を プログレスバーで表示してみる。
学習時にバーを表示させる
pytorchを使って、ニューラルネットワークを学習させる時に、 プログレスバーを表示させて、学習状況を見やすくしてみる。
バージョン
import tqdm import torch import torchvision print(tqdm.__version__) print(torch.__version__) print(torchvision.__version__)
出力
4.43.0 1.4.0 0.5.0
tqdmのバージョンを4.38.0?では、 学習の途中で無限ループのような感じになった。 なので、tqdmのバージョンを上げて、4.43.0で実行すると、 きちんと動くようになった。
import文とパラメータ
import文
import torch import torch.nn as nn import torch.optim as optim import torchvision import torchvision.transforms as transforms from tqdm import tqdm
パラメータの変数を宣言する。gpuありで学習した。 クラス数は、今回用いたデータセットCIFAR10の10クラス。epoch数は、 学習状況を少しみたいだけなので、少なくした。 batch sizeとlrは適当にした。
device=torch.device("cuda" if torch.cuda.is_available() else "cpu") batch_size=128 num_classes=10 num_epochs=20 lr=0.1
データセットの用意
データセットの用意をする。
今回は、画像識別のデータセットのCIFAR10を用いた。
データセットを読み込み時に変更するtransformは、画像をtensor形式にするToTensor()
のみにした。
CIFAR10()
でデータをダウンロードし、使えるようにする。
その後、データをまとめて処理できるようにbatch_size分を読み出すdataloaderを作り、データの準備は終わり。
transform={ "train":transforms.Compose([ transforms.ToTensor(), ]), "test":transforms.Compose([ transforms.ToTensor(), ]) } dataset={ "train":torchvision.datasets.CIFAR10(root="CIFAR10",train=True,transform=transform["train"],download=True), "test":torchvision.datasets.CIFAR10(root="CIFAR10",train=False,transform=transform["test"],download=True) } dataloader={ "train":torch.utils.data.DataLoader(dataset["train"],batch_size=batch_size,shuffle=True,num_workers=2), "test":torch.utils.data.DataLoader(dataset["test"],batch_size=batch_size,shuffle=False,num_workers=2) }
モデル、optimizer、ロス関数を用意
ネットワークはresnet18を使用した。最後の出力の数を、データセットのクラス数の10クラスへと 変えて、前に宣言したdeviceへ送る。optimizerはadamでロス関数はcross entropy lossを使用した。
model=torchvision.models.resnet18(pretrained=False)
model.fc=nn.Linear(model.fc.in_features,num_classes)
model=model.to(device)
optimizer=optim.Adam(model.parameters(),lr=lr)
criterion=nn.CrossEntropyLoss()
学習でプログレスバー表示
学習部分のコード。 1epochごとに、学習とテストを行う。 データローダーでバッチごとに処理をしていくたびにプログレスバーを更新していくように している。
tqdm()
でバーを表示できるようにする。今回は手動でバーを更新する方法を使った。
引数のtotal
に繰り返しの合計数などを入れ、繰り返し時にupdate(n)
でバーをnだけ進めて行く。
今回はdataloader
のサイズ、バッチごとに処理する回数を入れた。
引数のunit
は入れた文字で処理速度の単位を変えることができる。今回はバッチごとの処理をしているので、batch
を入れた。\
set_description(f"Epoch[{epoch}/{num_epochs}]({phase})")
で、
バーの前側の部分に現在のepoch数と最終のepoch数、
trainかtestかを表示するようにしている。文字列の前にfを付けることで、{}で囲んだ中に変数を入れることで、
変数の値を表示できて便利である。\
set_postfix({"loss":running_loss.item(),"accuracy":accuracy })
でバッチごとに学習またはテストした途中の段階でのlossと精度accuracyを更新している。\
最後に、バッチ1つ分の処理が終了したので、update(1)
でバーを1進め、totalになるまで繰り返す。
def train(model,dataloader,otpimizer,criterion,num_epochs,device): for epoch in range(1,num_epochs+1): for phase in ["train","test"]: if phase=="train": model.train() elif phase=="test": model.eval() with torch.set_grad_enabled(phase=="train"): loss_sum=0 corrects=0 total=0 with tqdm(total=len(dataloader[phase]),unit="batch") as pbar: pbar.set_description(f"Epoch[{epoch}/{num_epochs}]({phase})") for imgs,labels in dataloader[phase]: imgs,labels=imgs.to(device),labels.to(device) output=model(imgs) loss=criterion(output,labels) if phase=="train": optimizer.zero_grad() loss.backward() optimizer.step() predicted=torch.argmax(output,dim=1) ## dimあってる? corrects+=(predicted==labels).sum() total+=imgs.size(0) #loss関数で通してでてきたlossはCrossEntropyLossのreduction="mean"なので平均 #batch sizeをかけることで、batch全体での合計を今までのloss_sumに足し合わせる loss_sum+=loss*imgs.size(0) accuracy=corrects.item()/total running_loss=loss_sum/total pbar.set_postfix({"loss":running_loss.item(),"accuracy":accuracy }) pbar.update(1)
学習を行うと、バーが表示され、lossとaccuracyが更新されているのがわかる。 進むにつれてlossが下がっていっており、 学習が進んでいるとわかる。予測時間も表示されるので、どれくらいで終わるかも予測しやすい。
train(model,dataloader,optimizer,criterion,num_epochs,device)
まとめ
実際の学習コードでプログレスバーを表示して、学習の進み具合を見れるようにしてみた。 実際にlossが下がっているかを確認でき学習の状況を把握しやすくなる。
ニューラルネットワーク学習時に進み具合を表示する簡単な方法
はじめに
ニューラルネットワークの学習で、進行度合を文字ではなく、 プログレスバーのような目で見える形にするとわかりやすい。 tqdmというライブラリを使い、学習経過をプログレスバーで簡単に表示できるので試してみる。
tqdmとは
簡単に、コマンドライン上にプログレスバーを表示でき、 経過時間と予測時間も表示してくれる便利なpythonライブラリ。
インストール方法
pip install tqdm
プログレスバーの表示
使用ライブラリとバージョン
プログレスバー表示
- tqdm : 4.38.0
試してみる
ニューラルネットワークの学習の時のことを考えて、試してみる。
datasetで1epoch分、つまりdatasetの数(下の例ではデータ6個分を学習するのを1epoch)だけ学習するとする。 下のコードのようにdatasetがあり、データを読み込み、 time.sleep()部分が学習部分とする。 このままだと、何も表示されず学習の結果がわかりにくい。 そこで、プログレスバーを表示して、学習状況を見やすくしてみる。
import time dataset=["a","b","c","d","e","f"] for data in dataset: time.sleep(0.5)
出力
上のコードに少し足すだけで、プログレスバーを表示できる。for文でのデータセットの部分をtqdm
でおおう。
tqdm
の引数は、iterable(反復可能)なもので、
range()
などを引数として入れられる。
これだけで、簡単にバーを表示できる。
表示は、進行度の%、処理した数と処理すべき合計数、経過時間、残り時間の予測、処理スピードなどの情報が表示される。
import time from tqdm import tqdm dataset=["a","b","c","d","e","f"] for data in tqdm(dataset): time.sleep(0.5)
出力
手動でプログレスバーを操作する方法もある。
tqdm
の引数のtotal
に合計値を入れ、tqdmのインスタンスpbarとする。
手動でupdate(n)
を使い、nだけ増やしていく。
dataset=["a","b","c","d","e","f"] with tqdm(total=len(dataset)) as pbar: for data in dataset: time.sleep(0.5) pbar.update(1)
出力
学習の時、現在の精度やlossなどの値も確認したいので、表示してみる。
情報を表示するには、set_postfix(dict)
を用いることで表示できる。
引数には、キーが表示したい名前、辞書の値が表示したい値の辞書をいれる。
dataset=["a","b","c","d","e","f"] accuracy=0 with tqdm(total=len(dataset)) as pbar: for data in dataset: time.sleep(0.5) accuracy=accuracy+10 pbar.set_postfix({"accuracy":accuracy}) pbar.update(1)
出力
また、学習には1epoch分だけでなく、何epochも行う。 これをバーで表示すると、何個もバーが連なり、 現在が何epoch目かがわからないようになる。
dataset=["a","b","c","d","e","f"] num_epochs=10 for epoch in range(1,num_epochs+1): #1epoch分の学習 with tqdm(total=len(dataset)) as pbar: for data in dataset: time.sleep(0.5) pbar.update(1)
出力
そこで、前側にepoch数を書いておくことで、現在の進行度がわかるようになる。
バーの前側に文字を表示するのは、set_description()
dataset=["a","b","c","d","e","f"] num_epochs=10 for epoch in range(1,num_epochs+1): #1epoch分の学習 with tqdm(total=len(dataset)) as pbar: for data in dataset: time.sleep(0.5) pbar.set_description(f"Epoch[{epoch}/{num_epochs}]") pbar.update(1)
出力
まとめ
学習の過程を見てわかりやすいように、プログレスバーで表示してみた。 データセットなどのiterableな部分をtqdmで包むだけで、 簡単に表示でき使いやすい。 ニューラルネットワークの学習にも使っていきたい。
Google Colab Proを使いたかった(使えなかった)
はじめに
Google ColabでGPU付でニューラルネットワークの学習を行っていたら、 約6時間ぐらいの所でプログラムが止まってしまった。 その後、再実行使用とすると下のようなGPUバックエンドに接続できませんとの表示が出た。
学習には時間がかかるので、6時間で止まってしまうとつらい。もう少し長く使えないかと探していると Google Colab Proがあることを知った。Google Colabは無料で使えるが、Pro版は、1カ月9.99ドル払うことで、より速いGPUに優先的にアクセス、より長時間、より多くのメモリを使用可能となるとある。
Google Colab Pro使いたかった
Google Colab Proの特徴として下の3つがある。
- GPU
- Colab ProはT4やP100など高性能なGPUを利用しやすい(使用上限は有り)。使用量の上限もProの方が多い。
- 接続時間最大
- 無料版: 12時間
- Pro : 24時間
- メモリ
- Pro: ハイメモリVMを使用可能(無料版の2倍のメモリとCPU)
月9.99ドルの低価格なのでリソース保障はなし。
これはすごく便利そうと思い、早速申し込もうとするが、 現在はColab Proは米国のみで利用可能であり、日本では使えないことがわかる。 書いてあるだけで、実際は使えるのではと思い、 試しに購入できないかと購入画面へと行くと、 どうやら米国の住所がいるようである。
残念。。。 米国の住所なんてないのであきらめた。 よさそうなプランなので使いたかった。
おわりに
stack overflow での回答で、他のGoogleのサービス同様に、最初に米国でローンチした後、他国への展開するかもしれないとある。 それを期待して、日本でもサービス開始するのを待ちたい。
PyTorchでOne Hotに変換する
はじめに
PyTorchでOneHotに変換する方法がわからなかったので調べた。
変換方法
One Hotに変換するには、torch.nn.functional
にあるone_hot()
という
関数を使うことで変換できる。
PyTorchのバージョンは、v1.1.0以降が必要。
引数に、入力に変換前のtensor
と、num_classes
にクラス数を
入る。
torch.nn.functional.one_hot(tensor, num_classes=-1)
ドキュメントをここです。
使い方サンプル
まず、必要なモジュールをインポートと、バージョンを確認しておく。
import torch import torch.nn.functional as F print(torch.__version__)
バージョンが表示され、1.4.0であった。 1.1.0以降なので、使える。
one_hotを使ってみる。
入力として、label
を用意した。
これは、値が3のみ入っているtensorである。この3をone hot表現へと変換してみる。
この入力のlabel
とクラス数(今回は、10クラスとしてみる)を
one_hot
関数の引数として入れることで、結果としてone hot表現が得られる。
label=torch.tensor(3) print("label:",label) one_hot=F.one_hot(label,num_classes=10) print("one hot:",one_hot)
結果は下のようになった。 元の3が、変換後は[0,0 ...0]と10クラス分の0が並んだものをindexが3の部分のみ1にした ものへと変換できている。
label: tensor(3) one hot: tensor([0, 0, 0, 1, 0, 0, 0, 0, 0, 0])
このone_hot関数は、引数のnum_classes
を省略することもできる。
省略した時の挙動を見てみる。
先ほどと同じく、label
を設定。
それを、次は、num_classes
の引数を省いたone_hot
関数に入れてみる。
label=torch.tensor(3) print("label:",label) one_hot=F.one_hot(label) print("one hot:",one_hot)
出力は下のようになった。
こちらも、ラベルの3からone hotへと変換できている。
しかし、num_classes
を指定した時とは違って、
出力されたtensorのサイズが4になっている。
これは、one_hot関数の引数のnum_classesに何も指定しないと入力の中で一番大きい値からクラス数が決定されるためである。
今回は、最大が3なので0から始めて3番目が1になるように、クラス数は4となり、one hotでは4つの値となっている。
label: tensor(3) one hot: tensor([0, 0, 0, 1])
このone_hot
関数は、複数の値にも対応している。
先ほどまでの、labelの値は3という1つの値のみだったが、
今回は、0,1,2,0,4という6つの値に適用してみる。
変更したのは、入力のtensorを複数に変更しただけである。
label=torch.tensor([0,1,2,0,4]) print("label:",label) one_hot=F.one_hot(label,num_classes=5) print("one hot:",one_hot)
結果は、下のようになった。 出力も複数出力されていて、それぞれのone hot表現を取得できている。
label: tensor([0, 1, 2, 0, 4]) one hot: tensor([[1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0], [1, 0, 0, 0, 0], [0, 0, 0, 0, 1]])
まとめ
PyTorchでOne Hotに変換する方法を調べた。
すでに、PyTorchで用意されていて、torch.nn.functional
を使うことで、
変換できる。使う時には、きちんと、引数にクラス数を指定しないと
入力の内容から自動でクラス数が推定されて結果がおかしくなると思うので
注意が必要。
imgaugでbounding boxを表示
はじめに
物体検出では、物体の位置を表示する方法として、検出した物体を矩形(bounding box、バウンディングボックス)で囲む方法がある。 そのbounding boxを表示する方法として、imgaugというライブラリを使って表示することができるので試してみた。
imgaugとは
画像拡張用のpythonライブラリ
画像にノイズを加えたり、クロップしたりなどできる。 その中にbounding box表示用の関数もある。
リンク
bounding boxの表示
使用ライブラリのバージョン
- torchvision: 0.5.0
- imgaug: 0.4.0
データの用意
画像とbounding boxの位置の情報を用意する。今回は、torchvisionのクラスを使い、Pascal VOCのデータセットを使用した。 Pascal VOCでは、bounding boxは左上の頂点と右下の頂点の座標で表されている。
画像(image
)とアノテーション情報(annotation
)を取得した。
アノテーション情報の中に、複数の物体の情報がはいっており、物体の名前とbounding boxの位置が含まれている。
import torchvision voc_dataset=torchvision.datasets.VOCDetection(root="VOCDetection/2012",year="2012",image_set="train",download=True) image,target=voc_dataset[0] annotation=target["annotation"]
画像を表示してみる。
from IPython.display import display display(image)
物体の情報を表示してみる。
print(annotation["object"])
[{'name': 'horse', 'pose': 'Left', 'truncated': '0', 'occluded': '1', 'bndbox': {'xmin': '53', 'ymin': '87', 'xmax': '471', 'ymax': '420'}, 'difficult': '0'}, {'name': 'person', 'pose': 'Unspecified', 'truncated': '1', 'occluded': '0', 'bndbox': {'xmin': '158', 'ymin': '44', 'xmax': '289', 'ymax': '167'}, 'difficult': '0'}]
2つの物体(horseとperson)があり、それぞれbounding boxの情報(bndbox
)をもっている。bounding boxの情報は左上の頂点の座標のxmin
とymin
、右下の頂点の座標のxmax
とymax
で表されている。
このbounding boxを画像上に表示してみる。
bounding boxの描画
アノテーション情報から物体の名前(obj["name"]
)、bounding boxの位置情報(xmin
、ymin
、xmax
、ymax
)を取り出す。
bb=BoundingBox(x1=xmin,y1=ymin,x2=xmax,y2=ymax,label=obj["name"])
で描画用のbounding boxを作成する。
引数はx1,y1,x2,y2で左上の座標(x1,y1)と右下の座標(x2,y2)を指定する。
引数のlabel
に表示したい名前を入れることもできる。
それをlist形式で、bb_list
に保存する。
BoundingBoxesOnImage()
で複数のbounding boxをまとめたものを作り、draw_on_image()
で画像に対してbounding boxを付け加えた画像を生成する。
BoundingBoxesOnImage()
の引数のshapeでは、(height,width,channel)の順の画像のshapeを入力する。
draw_on_image()
での返り値は、ndarrayの画像なので表示するためにPILの画像に変換して表示した。
from imgaug.augmentables.bbs import BoundingBox,BoundingBoxesOnImage from PIL import Image bb_list=[] for obj in annotation["object"]: box=obj["bndbox"] xmin,ymin=float(box["xmin"]),float(box["ymin"]) xmax,ymax=float(box["xmax"]),float(box["ymax"]) #bounding boxを作成 bb=BoundingBox(x1=xmin,y1=ymin,x2=xmax,y2=ymax,label=obj["name"]) bb_list.append(bb) image_shape=(image.height,image.width,3) #imageにbounding boxを描画 bbs=BoundingBoxesOnImage(bb_list,shape=image_shape) bbs_image=bbs.draw_on_image(image,color=(255,255,255)) # 表示するためにpil形式に変換して、表示する pil_bbs_image=Image.fromarray(bbs_image) display(pil_bbs_image)
得られた画像はきちんと、物体の周囲にbounding boxが表示され、その上側に設定した名前が表示されている。
おわりに
imgaugを使ってbounding boxを表示してみた。 ラベル付きでbounding boxを表示できる関数が手軽に使えて便利。物体ごとに色を変えたいので、 できる方法がないか調べていきたい。
参考
TorchvisionでIoUの計算
はじめに
物体検出の評価指標で使われたりしているIoUを求めてみた。
IoUとは
Intersection over Unionの略である。Jaccard indexとも言われている。
物体検出の評価指標などで使われている。 物体検出では、物体を矩形で囲むことで、物体の位置を予測する。 正解もまた、矩形で囲まれたものが与えられる。この予測した矩形と正解の矩形を 評価する手法の1つとして、IoUが使われる。
2つの矩形があり、重なった部分の面積を面積の和で割ったものがIoUである。
2つの矩形が、まったく重ならなかったらIoU=0
となり、完全に重なるとIoU=1
となる。
IoUを求めてみる
IoUを求めてみる。
バージョン
- PyTorch : 1.4.0
- Torchvision : 0.5.0
使った関数
torchvision.ops.boxes.box_iou(boxes1,boxes2)
torchvisionにはtorchvision.ops.boxes
にbox_iou(boxes1, boxes2)
という関数がある。ドキュメントには載っていないが使えるので使う。
引数が矩形のboxes1とboxes2でそれぞれサイズがTensor[N, 4]、Tensor[M, 4]である。 この4の所は矩形の座標で(x1,y1,x2,y2)である。 返り値はiouでサイズがTensor[N, M]のテンソルである。
Google Colabで試した
矩形を2つ用意する。 最も左上の座標を(0,0)として右方向、下方向が+となる方向。 それぞれ左上の座標と左下の座標で矩形を表している。
一方の矩形にもう一方の矩形が含まれている例
box1は(0,0),(3,3)の矩形(黄色)、box2は(0,0),(5,5)の矩形(青)。
import torchvision.ops.boxes as bops box1=torch.tensor([[0,0,3,3]],dtype=torch.float) box2=torch.tensor([[0,0,5,5]],dtype=torch.float) print("box1:",box1) print("box2:",box2) area1,area2=bops.box_area(box1),bops.box_area(box2) print("area1:",area1) print("area2:",area2) iou=bops.box_iou(box1,box2) print(iou)
実行してみる。
box1: tensor([[0., 0., 3., 3.]]) box2: tensor([[0., 0., 5., 5.]]) area1: tensor([9.]) area2: tensor([25.]) tensor([[0.3600]])
重なり部分の面積=(3-0)(3-0)=9、和の部分の面積=(5-0)(5-0)=25となる。
その結果、 となる
2つの矩形が重ならない例
box1:(5,0),(8,3)で、box:(0,0),(5,5)の場合
box1=torch.tensor([[5,0,8,3]],dtype=torch.float) box2=torch.tensor([[0,0,5,5]],dtype=torch.float) print("box1:",box1) print("box2:",box2) iou=bops.box_iou(box1,box2) print(iou)
実行してみる。
box1: tensor([[5., 0., 8., 3.]]) box2: tensor([[0., 0., 5., 5.]]) tensor([[0.]])
重なっている部分がないので、IoU=0となる。
一部が重なる例
box1:(3,1),(6,4)で、box:(0,0),(5,5)の場合
box1=torch.tensor([[3,1,6,4]],dtype=torch.float) box2=torch.tensor([[0,0,5,5]],dtype=torch.float) print("box1:",box1) print("box2:",box2) iou=bops.box_iou(box1,box2) print(iou[0][0].item()) print(iou)
実行してみる。
box1: tensor([[3., 1., 6., 4.]]) box2: tensor([[0., 0., 5., 5.]]) 0.2142857164144516 tensor([[0.2143]])
重なり部分の面積は6、和の部分の面積は28なので、 となる。
入力のboxesが複数ある例
boxes1:(3,1),(6,4)の黄色の矩形と(1,3),(4,5)の紫の矩形 で、boxes2:(0,3),(2,6)の赤の矩形と(0,0),(5,5)の青の矩形の場合
boxes1=torch.tensor([[3,1,6,4],[1,3,4,5]],dtype=torch.float) #黄, 紫 boxes2=torch.tensor([[0,3,2,6],[0,0,5,5]],dtype=torch.float) #赤, 青 print("boxes1:",boxes1) print("boxes2:",boxes2) iou=bops.box_iou(boxes1,boxes2) print(iou)
出力は、
boxes1: tensor([[3., 1., 6., 4.], [1., 3., 4., 5.]]) boxes2: tensor([[0., 3., 2., 6.], [0., 0., 5., 5.]]) tensor([[0.0000, 0.2143],[0.2000, 0.2400]])
返り値のIoUは入力サイズのboxes1が2、boxes2が2より、2x2のtensorが返ってくる。
得られたIoUのtensorは下の表のようになる。縦がboxes1で横がboxes2の並びとなる。
(0,3),(2,6) 赤 | (0,0),(5,5) 青 | |
---|---|---|
(3,1),(6,4) 黄色 | 0.0 | 0.2143 |
(1,3),(4,5) 紫 | 0.2000 | 0.2400 |
つまり、iou[index1][index2]でboxes1[index1]とboxes2[index2]の2つの矩形のIoUを得られる。
つまった点
box_iouの入力のbox1,box2をdtype=torch.intのtensorで計算すると、結果が0になってしまう。 そのため、dtypeはfloatにする必要がある。
まとめ
IoUについて調べ、torchvisionのbox_iou関数を使ってIoUを求めてみた。 複数の矩形のIoUを一括で求められて便利。 今後は、物体検出の評価指標は他にも色々あるので調べてみたい。
参考サイト
PyTorchでPascal VOCデータセット を使ってみた
はじめに
Object DetectionのデータセットPascal VOCデータセットをPyTorchで使ってみた。
Pascal VOCとは
Pattern Analysis, Statistical Modelling and Computational Learning(PASCAL) Visual Object Classes Challenge(VOC)。 2005年~2012年に開催されていた物体のクラス認識などのコンペティション。 物体検出やセグメンテーションなどのタスクがある。
クラス数は2007年からは20クラス。
- Person: person
- Animal: bird, cat, cow, dog, horse, sheep
- Vehicle: aeroplane, bicycle, boat, bus, car, motorbike, train
- Indoor: bottle, chair, dining table, potted plant, sofa, tv/monitor
その中で今回は、物体検出のデータセットを使ってみた。
VOCDetectionクラス
PyTorchでPascal VOCのデータセットを使うのに、 Torchvisionの VOCDetection というクラスがある。 Pascal VOCのデータを簡単に読み込めるようなクラスが用意されている。 これを使ってみた。
クラスは下のような引数をとる。
torchvision.datasets.VOCDetection(root, year='2012', image_set='train', download=False, transform=None, target_transform=None, transforms=None)
torch.utils.data.Datasetのサブクラスで、
データを得る__getitem__
と、
データセットの大きさを得る __len__
を持っている。
引数は下のようなもの。
引数名 | 説明 | 値 |
---|---|---|
root | データセットのルートフォルダー | (e.g.) ./VOCDetection |
year | どの年のデータセットか | 2007, 2008, 2009, 2010, 2011, 2012 |
image_set | データセットの区分 | train, trainval, val |
download | データセットをダウンロードするかどうか | True, False |
transform | 画像に対して変形を行う際のtransform関数 | None(何もしない), torchvision.transforms.ToTensor()など |
target_transform | targetに対して変形を行う際のtransform関数 | None(何もしない) など |
transforms | transformとtarget_transformを合わせたようなやつ。?なんで必要なのこれ? | None(何もしない)など |
year=2007
の時のみ、image_set="test"
も使える。
indexでアクセスできる。 返り値は、(image,target)で、imageはPILの画像、targetはxml treeの辞書となっている。 targetには画像サイズやbounding boxの位置などの情報が入っている。
試してみた
バージョン
PyTorch: 1.4.0
Torchvision : 0.5.0
Google Colabで実行
まずは、データセットクラスを宣言。2012年のデータセットのtrainを使う。
download=True
なので、実行するとデータがrootで指定した./VOCDetection/2012
にダウンロードされる。
import torchvision voc_dataset=torchvision.datasets.VOCDetection(root="./VOCDetection/2012",year="2012",image_set="train",download=True)
データセットから一番最初のデータを取得する。 返り値は、画像とアノテーション情報である。
image,target=voc_dataset[0]
データセットの画像を表示してみる。
from IPython.display import display display(image)
次に、アノテーション情報targetについて見てみる。 targetを表示してみると、下のような辞書の形でアノテーション情報が入っている。
{'annotation': {'folder': 'VOC2012', 'filename': '2008_000008.jpg', 'source': {'database': 'The VOC2008 Database', 'annotation': 'PASCAL VOC2008', 'image': 'flickr'}, 'size': {'width': '500', 'height': '442', 'depth': '3'}, 'segmented': '0', 'object': [{'name': 'horse', 'pose': 'Left', 'truncated': '0', 'occluded': '1', 'bndbox': {'xmin': '53', 'ymin': '87', 'xmax': '471', 'ymax': '420'}, 'difficult': '0'}, {'name': 'person', 'pose': 'Unspecified', 'truncated': '1', 'occluded': '0', 'bndbox': {'xmin': '158', 'ymin': '44', 'xmax': '289', 'ymax': '167'}, 'difficult': '0'}]}}
画像のサイズ、物体の名前と位置などを使うので取り出してみる。 bounding boxの情報は、画像の一番左上のピクセルを(1,1)とした座標であり、左上の頂点と右下の頂点の情報で保持されている。
annotation=target["annotation"] #画像サイズ width, height, depth = annotation["size"].values() #物体の情報 objects=annotation["object"] for obj in objects: name=obj["name"] bndbox=obj["bndbox"] #bounding boxの左上と右下の座標 x_min,y_min,x_max,y_max=[int(val) for val in bndbox.values()]
画像とbounding boxが得られたので、画像上にbounding boxを表示してみる。 bounding boxの適用した画像を作る関数をつくる。もしかしたら、すでに便利な関数があるかもしれないが、 少し調べた範囲ではわからなかった。
from PIL import Image,ImageDraw def make_bbox_img(pil_image,x0y0,x1y1,text,width=1,color="red"): bbox_img=pil_image.copy() d=ImageDraw.Draw(bbox_img) d.rectangle((x0y0,x1y1),outline=color,width=width) #テキストのライン d.text((x0y0[0]+1,x0y0[1]+1),text,fill="white") d.text((x0y0[0]-1,x0y0[1]-1),text,fill="white") #テキスト d.text(x0y0,text,fill="black") return bbox_img name_to_color={ "person":"orange", "bird":"darkcyan", "cat":"lightyellow", "cow":"coral", "dog":"dimgray", "horse":"darkgreen", "sheep":"wheat", "aeroplane":"red", "bicycle":"royalblue", "boat":"blue", "bus":"yellow", "car":"hotpink", "motorbike":"lawngreen", "train":"cyan", "bottle":"olive", "chair":"indigo", "diningtable":"maroon", "pottedplant":"mediumslateblue", "sofa":"purple", "tvmonitor":"lime", } def make_voc_bbox_img(pil_image,objects,width=1): bbox_img=pil_image.copy() d=ImageDraw.Draw(bbox_img) #list形式でないものがあるのでlist形式へ直す if not isinstance(objects,list): objects=[objects] for obj in objects: name=obj["name"] bndbox=obj["bndbox"] x_min,y_min,x_max,y_max=[int(val) for val in bndbox.values()] color=name_to_color[name] #x:[1,image_width],y:[1,image_height] bbox_img=make_bbox_img(bbox_img,(x_min-1,y_min-1),(x_max-1,y_max-1),text=name,color=color,width=width) return bbox_img
先ほどの画像に適用してみる。
bbox_img=make_voc_bbox_img(image,objects) display(bbox_img)
うまくbounding boxを表示出来ている。 色が見にくいなどはあるが、表示できるようになったので、まあよしとする。 bounding box表示方法は、簡単な方法がないか探していきたい。
数枚の画像で試してみた。
つまづいた点
つまづいた点としては下のものがある。
- annotationのbounding boxの座標の値がstr型
- annotationのobjectの値が、全てlist形式と思っていたが、
objectが複数あるものはlist形式で、単一のものはlist形式でない点。
まとめ
PyTorchで物体検出を試してみたくて、Pascal VOCデータセットについて調べて動かしてみた。 データ形式などがわかった。 すでにクラスが用意されているので、自分でデータセットの読み込みなどを書く必要がなくて便利。 bounding box表示の関数がないか今後調べていきたい。
TensorBoardにおけるデータのSmoothingのアルゴリズム
はじめに
tensorboardでスカラー表示のグラフのところに、smoothingを変更するスライダーがある。 名前的に滑らかさを調節するスライダーということはわかるが、どんなアルゴリズムで滑らかにしてるんだろうと思ったので調べた。
smoothingのアルゴリズム
stack overflowでの回答
stack overflowで回答されているのを見つけた。
ここでの回答によれば、exponential moving average(指数移動平均)というものが使われているらしい。
wikipediaによると、
重みは指数関数的に減少するので、最近のデータを重視するとともに古いデータを完全には切り捨てない(重みは完全にゼロにはならない)。
というものらしい。
時刻tでの値をY[t]とする。時刻tでの指数移動平均をS[t]、係数aとすると、
S_[t] = a * Y_[t-1] + (1 - a) * S_[t-1]
で計算できる。参照元のページも見てみると、 0<=a<1とあり、Y[t-1]はY[t]に置き換えたものもあると書いてある。
tensorboardでの実装
tensorboardのリポジトリでsmoothingしてところ探した。 ここのresmoothDatasetで行っているようだ。
コードで試す
[1, 2, 3, 4, 4, 6, 5, 3]の値にsmoothingしてみる。
scalars=[1,2,3,4,4,6,5,3]
tensorboardのsmoothingの値を0.2にした値は、
[1, 1.833, 2.774, 3.756 ,3.951, 5.59, 5.118, 3.424]
となった。
stack overflowにあった関数をpythonで書いたもの
def smooth(scalars,weight): last=scalars[0] smoothed=[] for point in scalars: smoothed_val=last*weight+(1-weight)*point smoothed.append(smoothed_val) last=smoothed_val return smoothed
weight=0.2で実行してみる。
smoothed=smooth(scalars,0.2) print(smoothed)
出てきたものは、[1.0, 1.8, 2.7600000000000002, 3.7520000000000002, 3.9504, 5.59008, 5.118016, 3.4236032000000005]
近い値は、出てきているが微妙に違う。
tensorboardのコード見に行って書いたのが下のもの。前のものと違う点は、
最初の値に0を使っている(last=0
)のと、debias_weightを計算して、値を保存するときに、smooth_valをdebia_weightで割っているところが違う。
このdebias使う理由は、コードのコメントにかいてある。詳しくはわからないが、偏りが生じるのでそれをなくしているものと捉えている。
def debias_smooth(scalars,weight): last=scalars[0] last=0 smoothed=[] for i,point in enumerate(scalars,start=1): smoothed_val=last*weight+(1-weight)*point last=smoothed_val debias_weight=1-weight**i smoothed_val=smoothed_val/debias_weight smoothed.append(smoothed_val) return smoothed
同様にweigh=0.2で実行する。
smoothed=debias_smooth(scalars,0.2) print(smoothed)
[1.0, 1.8333333333333337, 2.7741935483870974, 3.756410256410257, 3.9513444302176697, 5.590373783922171, 5.118068711279505, 3.423609404440076]
となった。
tensorboard上の値と桁を整えれば一致している。
メモ
stack overflowのコードを式に直したら少し違っていたけど、よく見てみると一緒だった。
wikipediaの式では、
S_[t] = a * Y_[t-1] + (1 - a) * S_[t-1]
となっていた。 コードを直すと、
S_[t] = weight * S_[t-1] + (1 - weight) * Y_[t]
となる。wikipediaの式と違っていたのであれっとなった。
式変形してみる。weight=1-a
とおく。
S_[t] = (1-a) * S_[t-1] + a * Y_[t]
順番入れ替えて、
S_[t] = a * Y_[t] + (1-a) * S_[t-1]
あと違う部分は、Y_[t]
の部分だけだが、wikipediaの参照元のページを見てみると、Y_[t-1]
をY_[t]
に置き換えているものもあるということだったので、
これはこのままでもよさそう。ということで、ほぼ一緒になった。
まとめ
tensorboardのsmoothing処理はexponential moving average(指数移動平均)を用いてsmoothing処理が行われていて、 この指数移動平均は、現在の値に重点を置いてsmoothingする方法である。
参考サイト
AI最先端技術を調べられるサイト
紹介
どんなの
Papwers With Code というサイト。現在のAI研究がどんな研究がされているのか見れる。 AI研究の最先端の論文のとコードのリンクがセットでのっている。論文はだいたいarxivというサイトにある論文のリンクが張ってある。arxivはプレプリントを投稿できるサイト。コードはgithubで公開されているもの。コードはない時もあれば、色々な人が再実装していて、複数ある時もある。フレームワークもpytorchやtensorflowなど様々。pytorchでの実装が欲しいけど、tensorflowの実装しかないこともある。
分野ごとのページ
Browse the State-of-the-Art in Machine Learning | Papers With Code
sota(state-of-the-art)は最先端という意味で、色々な分野の最先端の研究を見つけられる。Computer Vision(画像とか動画とか扱っている)やNatural Language Processing(自然言語処理)などの分野にわかれていて、その中にその分野のタスクがある。Computer Visionの分野だと、Image Classification(画像分類) やObject Detection(物体検出)などのタスクがある。
タスクページ
そのタスクの中の1つimage classificationのページでを見てみる。image classificationのタスクは、与えられた画像に1つのラベルを割り当てていくタスクで、猫画像なら猫というラベルを付けるタスク。leaderboardにそのタスクごとのデータセットがのっている。image classificationのデータセットは、mnist(0から9までの10クラスのラベルが割り振られた白黒画像)やImageNet(1000クラスのラベルが割り振られた画像)などがあり、それぞれ個別のページがある。
データセットページ
ImageNetというデータセットのページを見てみると、上のグラフに円がいくつもある。この円が提案された手法で、横軸が提案された時期で、縦軸がデータセットでの指標となるもので、今回の場合は精度。一番上の線で結ばれているものがsotaのものの推移。 様々な手法が提案されて、精度が上がっていっていることがわかる。しばらくしてまた見に来ると、新しいものが出てきて、sotaになってたりする。進歩がすごく早い。
上の画像の下部分にあるのが、論文とコードがセットになった表で、精度が高い順番に並んでいる。
個人的に気になった研究
Lipreading
唇から言ってることを読み取って文字にする研究
タチコマが唇から読み取っていたのを思い出した。未来感がある。 どこまで読み取れるのかは、リーダーボードがなかったのでわからない。
Face Generation
存在しない人の顔の画像を作る研究
ほぼ、本物の人と見分けがつかないくらいきれいに作れてるのがすごい。 アニメ画像作りたいので、このへんの勉強しなくちゃ。
Code Generation
コード生成の研究
pix2codeのデモが面白かった。 UIのスクリーンショット画像から、htmlを作っていた。 www.youtube.com
おわりに
色々な分野の研究がまとめられているので、どんな研究がなされているのかをぱっと知るのに役に立つ。 論文とコードのリンクもセットでついてるのでとても便利。 また、タスクごとのデータセット調べたりする使い方もできる。
Safebooruからアニメ画像ダウンロード
はじめに
GANでアニメ画像生成したい。そのためには、データとして大量のアニメ画像を集める必要がある。 スクレイピングするのと、動画のSSとる方法があるが、今回は、楽そうな方のスクレイピングで画像集めることにした。
前にアニメデータセット探した中で、sabebooruというサイトを知った。 https://msdd.hatenablog.com/entry/2019/11/21/235937msdd.hatenablog.com
sabebooruは、画像のアーカイブをタグ付きで保存してあるサイトで、検索もできる。
画像が大量に欲しいので、このサイトからダウンロードすることにした。
画像ダウンロード
apiがあったので、それを使った。
api アクセスのurl: https://safebooru.org/index.php?page=dapi&s=post&q=index
limit:どれだけの投稿を検索するか。max100。
pid : ページ数。
tags: 検索するタグ。
などを追加して検索できる。 とりあえず、https://safebooru.org/index.php?page=dapi&s=post&q=indexにアクセスしてみると、xmlが表示されたので、pythonでxmlを扱って、urlから画像ダウンロードするスクリプト作った。
api_strはページ番号pidと検索するtagsを設定した文字列で、これを送りxmlを取得する。
今回は、一人の顔画像が欲しいので、タグはface 1girl solo
のものをダウンロードすることにした。
api_str="https://safebooru.org/index.php?page=dapi&s=post&q=index&pid={pid}&tags={tags}".format(pid=page,tags=request_tags.replace(" ","+")) with urllib.request.urlopen(api_str) as response: content=response.read()
pythonのxmlはElementTreeというもので扱うようだ。xmlをパースした後、それぞれ投稿の画像urlを取得した。一回のリクエストで、100件得られる。
xml=ET.fromstring(content) for post in xml.iter("post"): file_url=post.get("file_url")
これを今回は50回ループさせて、5000枚集めた。サイズは3.3G。集めた画像のサンプルが下の画像。
きちんと、一人のキャラの顔が写っている画像を集めることができた。
今後
このデータを使ってGANでアニメ画像生成していきたい。
コード置き場
参考サイト
PyTorchのネットワーク構造を可視化できるものを探してみた
はじめに
PyTorchでネットワーク構造を見たいけど、何使えばいいかわからなかったので、探した。
import torch import torch.nn as nn import torch.nn.functional as F class TestModel(nn.Module): def __init__(self): super().__init__() self.fc1=nn.Linear(10,5) self.fc2=nn.Linear(5,2) def forward(self,x): x=F.relu(self.fc1(x)) x=F.softmax(self.fc2(x)) return x model=TestModel() print(model)
テストで使うネットワーク。FC層2層のテストモデル。
TestModel( (fc1): Linear(in_features=10, out_features=5, bias=True) (fc2): Linear(in_features=5, out_features=2, bias=True) )
可視化手法
1. onnxに変換してnetronで見る
まず、pytorchのモデルをonnx形式に変換する。
dummy_input=torch.randn(1,10)#ダミーの入力を用意する input_names = [ "input"] output_names = [ "output" ] torch.onnx.export(model, dummy_input, "./test_model.onnx", verbose=True,input_names=input_names,output_names=output_names)
実行すると、下のような出力とtest_model.onnxというonnxファイルが出力される。
graph(%input : Float(1, 10), %fc1.weight : Float(5, 10), %fc1.bias : Float(5), %fc2.weight : Float(2, 5), %fc2.bias : Float(2)): %5 : Float(1, 5) = onnx::Gemm[alpha=1, beta=1, transB=1](%input, %fc1.weight, %fc1.bias), scope: TestModel/Linear[fc1] # /usr/local/lib/python3.6/dist-packages/torch/nn/functional.py:1370:0 %6 : Float(1, 5) = onnx::Relu(%5), scope: TestModel # /usr/local/lib/python3.6/dist-packages/torch/nn/functional.py:914:0 %7 : Float(1, 2) = onnx::Gemm[alpha=1, beta=1, transB=1](%6, %fc2.weight, %fc2.bias), scope: TestModel/Linear[fc2] # /usr/local/lib/python3.6/dist-packages/torch/nn/functional.py:1370:0 %output : Float(1, 2) = onnx::LogSoftmax[axis=1](%7), scope: TestModel # /usr/local/lib/python3.6/dist-packages/torch/nn/functional.py:1317:0 return (%output)
onnx形式に変換後、Netronというもので可視化できる。こののページにonnxファイルをアップロードするとネットワーク構造が見れる。
層の名前は変わってしまうが、きちんと表示されている。
このnetronはonnxに変換せずにもpytorchの保存したファイルでも表示はできるみたい。しかし、サイトには実験的サポートと書いてある。
torch.save(model,"./test_model.pth")
保存されたファイルをアップロードしてみると、ネットワーク構造は表示されたが、relu、log_softmaxが表示されなかった。
2. tensorboard
tensorboardのグラフ表示する機能を使う方法。
google colabのtensorflowのバージョンを2系へ変更して、 tensorboardの拡張を読み込む。
%tensorflow_version 2.x %load_ext tensorboard
add_graphを用いて、モデルの構造の出力する。
from torch.utils.tensorboard import SummaryWriter dummy_input=torch.randn(1,10) writer = SummaryWriter() writer.add_graph(model, dummy_input) writer.close()
tensorboardを起動して、グラフを見る。
%tensorboard --logdir ./runs
ダブルクリックすると、中身も見れる。
3. pytorchvizで見る
pytorchvizを使い、モデルを可視化する。
ライブラリをインストールする。
!apt-get install graphviz !pip install torchviz
次に、モデルを生成し、入力xを通して出力yを得る。 make_dotの引数に出力とモデルのパラメータを入れると、グラフが出てくる。
from torchviz import make_dot model=TestModel() x=torch.randn(1,10)#ダミー入力 y=model(x) make_dot(y,params=dict(model.named_parameters()))
参考サイト
Google Colab上でTensorBoardを使う
はじめに
google colab上でtensorboardを使えるみたいだったので、試してみた。
環境
- 使用ブラウザ: Firefox 71.0
- torch 1.3.1
- torchvision 0.4.2
tensorboard関連のライブラリわからないけど、一応。
- tensorflow 2.1.0rc1
- tensorboard 2.1.0
- tensorboardcolab 0.0.22
実行
ログファイルの準備
今回は、pytorchのtorch.utils.tensorboardを使ってログファイル作った。
tensorflowのバージョンを2系に切り変えておく。
%tensorflow_version 2.x
ログファイルの作成。グラフとスカラー値をログを作った。 グラフは、mobilenet v2のモデルを記録した。
import torch from torch.utils.tensorboard import SummaryWriter import torchvision.models as models model=models.mobilenet_v2() image=torch.randn(1,3,224,224) writer = SummaryWriter() writer.add_graph(model, image) writer.add_scalar("test",1,1) writer.add_scalar("test",2,2) writer.close()
実行すると、runsというフォルダーが出来て、ログが入っている。 これをtensorboard上に表示させてみる。
tensorboardを起動する準備
tensorboard notebookの拡張を読み込む
%load_ext tensorboard
tensorboard起動
%tensorboard
でtensorboarを起動する。--logdir
の後に生成したログフォルダの場所を指定する。
%tensorboard --logdir ./runs
SCALARSにきちんと追加した値がグラフとして表示されている。
GRAPHSの方もmobilenet v2の構造が表示されている。
気になる点、今後
firefoxのプライベートウィンドウで実行すると、下のように403が表示された。
chromeのシークレットウィンドウでも同じことになるのかと思って試してもならなかった。 原因はわからなかった。
学習結果をすぐに見れるのは便利なので、今後学習の時に使っていきたい。
参考サイト
Google Colabで使われているgpuの種類の調査
はじめに
Google ColaboratoryにはGPUガチャがあるよという話 - Qiita
この記事読んで、google colabのgpuでも色々な種類のものがあることを知った。
画像や動画でdeep learningをする時、gpuの性能が重要なことが多い。 deep learningの学習は、多くの時間がかかり、 google colabは、時間制限がある。 そのため学習時は、出来るだけ性能のいいgpuを使いたい。 そこで、どのようなgpuがあるのかを調べてみた。
調べ方は簡単で、コマンド!nvidia-smi
名前長くて見れないやつは!nvidia-smi -L
で
gpuの名前見て、その名前を検索して調べた。
このコマンドは、gpuの名前や使用率を見ることができるコマンドで、よくgpu使用率を見る時に
使用している。
gpuの調査
gpuの種類
実際にgoogle colabを使っていて、割り当てられたものは下のようになった。
自分でgoogle colabを使用していたが、割り当てられたのを見たことがない、未確認のものは下のようになった。
- Tesla T4
全てNvidia Teslaシリーズであった。
短くにまとめてみる。 注意点としては、Tesla K80は2つのgpuのうち1つのみ使えるらしく、Nvidiaの実際のスペック表に書いてあるものの半分だけ使えると思われる。 下の表には半分にした値を載せた。
GPU名前 | 発売日 | メモリ容量 | CUDAコアプロセッサ数 | 単精度浮動小数点性能 | |
---|---|---|---|---|---|
Tesla K80 | 2014年11月 | 12GB | 2496 コア | 4.37 TFLOPS (GPU Boost Clocks), 2.8 TFLOPS (Base Clocks) | |
Tesla P100-PCIE-16GB | 2016年6月 | 16GB | 3584 コア | 9.3 TFLOPS(最大ブースト) | |
Tesla P4 | 2016年9月 | 8GB | 2560 コア | 5.5 TFLOPS(最大ブースト) |
wikipediaを参考にした。
この表を見てみると、メモリ容量に関しては、P100がP4の2倍の16GBもあり、かなり容量が多い。 deep learningでは、メモリを多く使うのでこれはうれしい。コア数でも、やはりP100が多い。 なので、計算速度もP100が速いと思われる。K80とP4は、どちらが速いのかはわからない。
GeForceシリーズと比較
Teslaシリーズは、普段は見ることがないので、よく見る方のgeforceシリーズと比べてみる。 TeslaシリーズのP100と比較した。 GeForceシリーズは、最近のものだとRTX 2080 super,RTX 2070 superなどや、前に売られていたGTX 1080などのシリーズ。
GPU名前 | 発売日 | メモリ容量 | CUDAコアプロセッサ数 | 単精度浮動小数点性能 | |
---|---|---|---|---|---|
Tesla P100-PCIE-16GB | 2016年6月 | 16GB | 3584 コア | 9.3 TFLOPS(最大ブースト) | |
RTX 2080 Ti | 2018年8月 | 11GB | 4352 コア | 12.4 TFLOPS | |
RTX 2070 SUPER | 2019年7月 | 8GB | 2560 コア | 8.2 TFLOPS |
wikipediaを参考にした。
P100と比べると、GeForce RTX 2080 Tiはメモリが5GBほど少ないが、P100より新しいのでコア数は多く演算は早いと思われる。
nvidia-smi
で取得したSS
おわりに
google colabで使われているgpuの種類をnvidia-smi
のコマンドを使って、名前を調べると、
NVIDIA Teslaシリーズのgpuが使われていることがわかった。
さらに、割り当てられたことのある3つのgpuについて、性能やメモリ容量などをまとめてみた。
メモリでは、P100>K80>P4の順で容量が大きく、P100がP4の2倍の16Gとかなり大きい。 計算速度もP100が速い。K80とP4は、どちらが速いのかはわからない。
無料で使わせてもらえるのはとてもありがたい。 ありがたく使わせてもらいますm( )m。
新しいの見つけたら更新していきます。