20210413のPythonに関する記事は30件です。

【小ネタ】Streamlit でクエリパラメータはexperimental_get_query_paramsで取得できる

はじめに 公式ドキュメントを検索しても使い方が見つからなかったのですが、Streamlit Version 0.65.0で追加されてるのを発見し使い方について調査したものを記事にまとめました。 クエリパラメータの取得方法 タイトルに記載の通り、experimental_get_query_params()メソッドにて取得可能です。 サンプルプログラム streamlit_app.py import streamlit as st params = st.experimental_get_query_params() # # 例: http://localhost:8501?name=abc&name2=5 の場合 # paramsには以下のように格納される # { # "name": [ # "abc" # ], # "name2": [ # "5" # ] # } お試しサイト こちらのサイトに検証用のサイトを構築しましたのでテストされたい方はアクセスしてみてください。 検証用サイトのソース サンプルプログラム streamlit_app.py import streamlit as st st.title('Streamlitでクエリパラメータを取得するサンプル') params = st.experimental_get_query_params() st.write('experimental_get_query_params() の実行結果') st.write(params) 検証用サイトのURL Appendix 参考サイト Changelog - Streamlit 0.65.0 documentation ご意見・ご感想をお待ちしております 今回の記事はいかがでしたか? ・こういう記事が読みたい ・こういうところが良かった ・こうした方が良いのではないか などなど、率直なご意見を募集しております。 頂いたお声は、今後の記事の質向上に役立たせて頂きますので、お気軽に コメント欄にてご投稿ください。Twitterでもご意見を受け付けております。 皆様のメッセージをお待ちしております。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ピアノウィジェットを作る

1.はじめに 自作MIDIスイッチャを作り変えるプロジェクトですが、 MIDIフィルタリング&スイッチするときに、 キーボードのスプリットとかがやりたいです。 (マスターキーボードの上半分はMIDI音源1に下半分はMIDI音源2に、とか) で、スプリットの指定をGUIでやるにあたって、 やっぱりピアノの鍵盤が表示されて、 ここからここまでね、ってカンジで指定したい!! そうなると、ピアノウィジェットがいるな、というわけで作ってみました。 あ、実装は相変わらずpython3 + pygtkです。 2.ピアノの鍵盤を描画する とりあえず、ピアノの鍵盤を描画しないといけないわけですが、 みなさん、ピアノの鍵盤がどういう図形か説明できますか?? まずはわかりやすいように1オクターブで考えます。 1オクターブの中に含まれるのは ドレミファソラシドの白鍵7つと黒鍵が5つです。 合計12個の鍵盤があります ドから順番に鍵盤番号(ノートナンバー)を0〜11までふったときに、 各鍵盤のノートナンバーに対応する鍵盤の矩形はどうなるのでしょうか? 左上を始点(begin_x,begin_y),白鍵盤の幅をwkey, 高さをhkeyとした場合に それぞれ値をもとめてみましょう。 2.1.ピアノの鍵盤の幅を求める まずは、wkeyとhkey,鍵盤の幅と高さですが、これはわりと簡単。 白鍵の幅(wkey): 鍵盤の全体の幅÷白鍵の個数(=7) 白鍵の高さ(hkey): 鍵盤の全体の高さ 黒鍵の幅: 白鍵の幅:wkey × 任意の倍率(0.6〜0.5ぐらい) 黒鍵の高さ: 白鍵の高さ:hkey × 任意の倍率(0.6〜0.5ぐらい) とします。 2.2.鍵盤の始点を求める で、左上の始点を求める場合は.... begin_yは白鍵盤、黒鍵盤ともに0でいいかなー 問題はX座標だけども、うーーん、 やっぱり黒鍵と白鍵で場合分けするしかないかな... というわけで、黒鍵か鍵か判定できるよう、 次の様な配列を用意しておきます。 NOTES_WHITE = [ 0, # ド 2, # レ 4, # ミ 5, # ファ 7, # ソ 9, # ラ 11, # シ ] もし、ノートナンバー in NOTES_WHITEなら白鍵、そうじゃなければ黒鍵です。 2.2.1 白鍵盤のときの始点 白鍵盤の場合のbegin_xは 白鍵盤の幅(wkey) × 白鍵盤の中の順番(開始は0番から) で求められます。 pythonで書くと begin_x = wkey * NOTES_WHITE.index(ノートナンバー) になります(鍵盤全体を7等分したときの、白鍵盤のうちの何番目かから求める)。 図で書くとこんなイメージです: 2.2.2 黒鍵盤のときの始点 次に黒鍵の場合ですが、少なくとも黒鍵の場合、ノートナンバーを-1すると、 隣に白鍵(音が低い方)があるので、それを基準に座標が求められます。 隣の白鍵盤の終点 = 隣の白鍵盤の始点 + wkey 黒鍵盤のbegin_x = 隣の白鍵盤の終点 - 黒鍵の幅 ÷ 2 コードで書くと # # 隣の白鍵盤の終点までをまずオフセット #  begin_x = wkey * NOTES_WHITE.index(ノートナンバー - 1) + wkey # # 黒鍵の幅だけ戻る # begin_x -= wkey * 0.6 / 2 です。 3.オクターブ増やすと?? オクターブが増えた時はどうなるかっていうと、 オクターブ数 = ノートナンバー ÷ 12 そのオクターブ中のノートナンバー(0〜11) = ノートナンバー mod 12 となるので、 黒鍵か白鍵かの判定は、ノートナンバー % 12の値を使って判定します。 あとはbegin_xにオフセットとしてオクターブ数×7×wkeyを足せばいいだけです。 まとめると begin_x = int(7 * wkey * (ノートナンバー / 12)) # オクターブ分X座標をオフセット # # ここから下は1オクターブしかないときとだいたい同じ # if (ノートナンバー % 12) in NOTES_WHITE: begin_x += wkey * NOTES_WHITE.index(ノートナンバー%12) else: begin_x += wkey * NOTES_WHITE.index(ノートナンバー%12 - 1) + wkey begin_x -= wkey * 0.6 / 2 4.じゃぁ座標からノートナンバーを求めるには?? じゃぁ逆にマウスで座標をクリックした所から ノートナンバーを求めるにはどうしたらいいでしょうか?? マウスがポイントした点を(x,y)として場合分けしてみます。 4.1.鍵盤が白鍵盤しかないと仮定してみると まずは、鍵盤の下の方をたたいたと仮定、すなわち、 ピアノの鍵盤が白鍵盤しかないと仮定して、 仮のノートナンバーを求めます。 yの値は無視してxに注目すると x ÷ wkey = (マウスがポイントした点までの)白鍵盤の数 octave = マウスがポイントした点までの白鍵盤の数 ÷ 7 (マウスがポイントした点の)オクターブ中のノートナンバー = NOTES_WHITE[白鍵盤の数 mod 7] ノートナンバー(仮) = octave × 12 + オクターブ中のノートナンバー となって、鍵盤がすべて白鍵盤と仮定したときのノートナンバー(仮)が出ます。 4.2.黒鍵押してるかどうかをを判定 次に、黒鍵がクリックされたか、白鍵盤がクリックされたか判定します。 すくなくとも黒鍵がクリックされた場合、 鍵盤の上の方がクリックされている必要があるので、 マウスの座標 y が 黒鍵の長さより短い場合は黒鍵をクリックしている可能性があります。 そうでない場合はノートナンバー(仮)がノートナンバーになります。 もし、鍵盤の上の方をクリックしている場合ノートナンバー(仮)に応じて処理が変わります 4.2.1.ドとファの場合 ノートナンバー(仮)より高い音側に黒鍵が存在する可能性があるので、 x がその範囲にあるかどうかを調べます。 高い音側が押されていたら、ノートナンバー(仮)を+1したものがノートナンバーになります。 そうでない場合はノートナンバー(仮)がノートナンバーになります。 4.2.2.ミとシの場合 ドとファの場合と逆に ノートナンバー(仮)より低い音側に黒鍵が存在する可能性があるので、 同じく調べます。 低いい音側が押されていたら、ノートナンバー(仮)を-1したものがノートナンバーになります。 そうでない場合はノートナンバー(仮)がノートナンバーになります。 4.2.3.それ以外の場合 高い音側と低い音側両方に黒鍵がある可能性があるので、 両方を調べます。ノートナンバーを決定します。 5.で、実装してみると そんなわけで色々盛り込んで結局実装するとこんなカンジになります。 諸般の事情でクッソ汚いソースですが,少しづつ理解を深めながら作っていったので、 最初の方に書いたコードとあとの方に書いたコードで わかりやすさにかなりの差があります。 縦方向に配置できたりとか、 クリックした場所にマーカーつけたりとか、 ドラッグして範囲を求めるウィジェットも作ってみました。 実行例はこんなカンジです: 6.感想 鍵盤を書くロジックは比較的簡単に求められたのですが、 マウスの座標からノートナンバーを計算するのはちょっと考えました。 最初に考えた時は x ÷ 鍵盤全体の幅 = 正規化した位置 ノートナンバー = 正規化した位置 × 全体の鍵盤の個数 で求められるかなーと思ったら、微妙にずれていて、 やっぱドミシの隣は黒鍵が少ないの考慮しないとダメかー、となりました。 オブジェクト指向らしく、ボタンウィジェット使って計算をサボろうかなとも考えましたが、 押した場所に赤色のマーカーで色付けしようと思った場合に、色々と面倒くさい1のでやめました。 ちなみに一ヶ月後にソース見たら、今回のロジック思い出せない自信はあります(笑)。 まぁ、そのためのカプセル化だからナ よく考えたら、鍵盤を描いたり、クリックして音を出すって 大昔からある実装なわけで、 フリーのシーケンスソフトとかを参照すれば、 もっとスムーズに出来たかもしれません。 まぁ、車輪の再発明も脳のトレーニングということでひとつ.... Gtk3だと色変えるのにわざわざCSSで指定しなきゃいけない(!!)わけです。Gtk2の頃はあんなに簡単だったのに.....。でも、そもそもウィジェットの色を変えるのはテーマの一貫性がなくなる可能性があるからやめといてね、という思惑もありそう。 ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

numpy の save と load で dict を扱う

はじめに numpy の配列を保存して読み込む.numpy.save と numpy.load 事が足りそうだ. ここでは,dict型のデータを扱う. 目的 numpy でデータを保存する.データの作成条件等を dict型で保存したい. 実験 失敗するコード 動きそうだがうまくいかないコード import numpy as np a = {'A':1, 'B':2, 'c':3} np.save('test.npy', a) b = np.load('test.npy') print(b['B']) エラー箇所 np.load で ValueError b['B'] で IndexError 配列aの確認 aは dict型 a, type(a) # ({'A': 1, 'B': 2, 'c': 3}, dict) allow_pickle パラメータ numpy.saveとnumpy.loadでは,必要であれば,Pythonのモジュールであるpickleを使用して配列情報を保存する. 関数 省略 初期値 numpy.save 可 True numpy.load 可 False numpy.load によると,version 1.16.3 にallow_pickle = Falseが標準になったらしい. allow_pickle: bool, optional Changed in version 1.16.3: Made default False in response to CVE-2019-6446. 改良したコード b = np.load('test.npy', allow_pickle=True) numpy オブジェクトと辞書 b['B']で'IndexError' bは dict型っぽく見えるが,実は object 型. b = np.load('test.npy', allow_pickle=True) b # array({'A': 1, 'B': 2, 'c': 3}, dtype=object) 改良コード. numpy.ndarray.item itemを使って値を取り出す. d = b.item() d['B'] # 2 まとめ 動作するコード a = np.array({'A':1, 'B':2, 'c':3}) np.save('test.npy', a) b = np.load('test.npy', allow_pickle=True) d = b.item() print(d['B']) # 2 参考 np.loadとnp.save関数でファイルの永続化方法
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Windows10にてAnacondaでspaCy入れようとするとアクセスが拒否される件について

経緯 表題の通りAnacondaを使ってspaCyを入れようとすると、プロンプトには「アクセスが拒否されました」とのエラーが...権限周りが引っかかっているのかなと仮定し、プロンプトを管理者権限で再起動してみたがエラー解決できませんでした。 解決策 こちらの記事に助けていただきました!感謝! easy_install -U pip 後、spaCyインストールできました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GiNZAで機械分析入門してみました

いままでMeCabを使っていたのですが、この度GiNZAに入門したので備忘録的なやつを書いときます。 GiNZAとはなんぞや 欧米で有名な自然言語処理ライブラリであるspaCyの日本語版(超ざっくり) 係り受け解析とか形態素解析とか色々できるっぽいです 環境 Python 3.6.5 pip 21.0.1 Mac Catalina 環境構築 今回は仮想環境にGiNZAをinstallして動かしていこうと思います。 ひとまず適当なフォルダをつくって $ mkdir sample $ cd sample venvで仮想環境を構築して中に入ります。 $ python -m venv venv $ source venv/bin/activate pipをアップデートして、Ginzaをインストールします。 (venv)$ pip install --upgrade pip (venv)$ pip install -U ginza インストールが完了したら念のため確認します。 (venv)$ pip list ・ ・ dartsclone 0.9.0 ginza 4.0.5 idna 2.10 ・ ・ ちゃんと入ってますね!! 動かしてみる さっそくスクリプト書いて形態素解析してみましょう。 今回は百人一首のあの有名な歌を解析してみます sample.py import spacy nlp = spacy.load('ja_ginza') doc = nlp('秋の田の 仮庵の庵の 苫をあらみ わが衣手は 露にぬれつつ') for sent in doc.sents: for token in sent: print(token.i, token.orth_, token.lemma_, token.pos_, token.tag_, token.dep_, token.head.i) 結果がこちらです (venv)$ python sample.py 0 秋 秋 NOUN 名詞-普通名詞-副詞可能 nmod 2 1 の の ADP 助詞-格助詞 case 0 2 田 田 NOUN 名詞-普通名詞-一般 nmod 6 3 の の ADP 助詞-格助詞 case 2 4     X 空白 3 5 仮 仮 NOUN 名詞-普通名詞-一般 compound 6 6 庵 庵 NOUN 接尾辞-名詞的-一般 nmod 8 7 の の ADP 助詞-格助詞 case 6 8 庵 庵 NOUN 名詞-普通名詞-一般 nmod 11 9 の の ADP 助詞-格助詞 case 8 10     X 空白 9 11 苫 苫 NOUN 名詞-普通名詞-一般 obj 13 12 を を ADP 助詞-格助詞 case 11 13 あら あり VERB 動詞-非自立可能 acl 18 14 み み NOUN 接頭辞 aux 13 15     X 空白 14 16 わが わが DET 連体詞 amod 17 17 衣 衣 NOUN 名詞-普通名詞-一般 nmod 18 18 手 手 NOUN 名詞-普通名詞-助数詞可能 ROOT 18 19 は は ADP 助詞-係助詞 case 18 20     X 空白 19 21 露 露 NOUN 名詞-普通名詞-一般 obl 23 22 に に ADP 助詞-格助詞 case 21 23 ぬれ ぬれる VERB 動詞-一般 ROOT 23 24 つつ つつ SCONJ 助詞-接続助詞 mark 23 一応解析できてますね!! ただ、「仮庵」とか「衣手」は一つの形態素として抽出してほしかったのですが、うまくいってないみたいです... MeCabと同様辞書登録が必要かもしれません。 とはいえ、特定の品詞に絞って抽出とかもできそうで色々と可能性を感じますねー! ざっくりでしたが今回はここまでです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PythonでPDFから表の取得(camelot)-社会保険料の標準報酬月額の取得に利用-

1.前置き この春、新社会人になりました。来たる給料日が非常に楽しみです。 給料のことを気にしていると、手取りも気になってきます。 予想したおおよその手取りよりも実際の手取りが少なかったら、少し悲しむ気がしてきました。 そんな理由で、手取りを正確に計算することで、心の平穏の維持に備えようと考えました。   さて、手取りを計算するためには、社会保険料と税額を求める必要があります。 この内の社会保険料は、月収を標準報酬月額に変換して、その値にある保険料率を掛け算することで求められます。 本記事では、PythonでPDFから表の取得を行うことで、社会保険料の計算に必要な標準報酬月額の取得を目指してみました。 2.ライブラリのインストール PythonでPDFから表を取得するための方法は、ざっと調べてみると二つありそうでした。 tabuler-pyライブラリもしくはcamelotライブラリを用いる方法です。 tabuler-pyは、ライブラリの中身はJavaで書かれているそうなので、PCにJava環境がないと動きません。 プログラミング環境は雑に作りたくないので、Java環境を作ってtabuler-pyを使うのは見送ることにして、今回はcamelotライブラリを使用しました。 camelotライブラリ自体は、 pip install camelot-py[cv] でインストールできます(Anaconda利用者は、pipでなくcondaで管理)。 ただこのライブラリの利用には、Ghostscriptが必要ですので、インストールしておきましょう。 For Windows : https://www.ghostscript.com/download/gsdnld.html For macOS : brew install tcl-tk ghostscript 3.PDFから表の取得 では、実際にcamelotを使って、PDFから表を取得しましょう。 今回は、厚生年金保険料計算のための標準報酬月額を調べるために、日本年金機構が出している保険料額表をサンプルとして取り上げてみます。 import camelot table_nenkin = camelot.read_pdf('nenkinR3.pdf') #TableList table_nenkin[0].df PDFをnenkinR3.pdfという名前で保存して、camelot.read_pdfに引き渡すと、 PDF中の全ての表がDataFrameとして取得され、ページ上部の表から順にリストへ格納されます。 本PDFは表が一つしかなく、table_nenkin[0].dfで目的の表をデータフレームとして取得できます。 この表をJupyter環境で表示すると下図のようになるはずです。 簡単ですね!! 表取得は完了しましたので、当初の目的通りに、これを標準報酬月額の取得に応用してみましょう。 以下コードと実行結果。 import re month_salary = 238000 # your salary for i in range(3,35): if i == 34: standard_month_salary = int(re.sub(r"\D", "", table_nenkin[0].df[1][i])) break s = table_nenkin[0].df[2][i] Range = s.split('\n') Range_H = int(re.sub(r"\D", "", Range[2])) if Range_H >= month_salary: standard_month_salary = int(re.sub(r"\D", "", table_nenkin[0].df[1][i])) break print('標準報酬月額(円):', standard_month_salary) 標準報酬月額(円): 240000 4. 最後に 社会常識のお勉強ついでに、Pythonを用いてPDFから表の取得をする方法を調べてみました。camelotの使い勝手は良さそうです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Python+SeleniumでNEOBANK(住信SBIネット銀行)の明細取得(CSVダウンロード)

PythonとSeleniumを使って、NEOBANK(住信SBIネット銀行)サイトにログインして明細データを取得(CSVダウンロード)する方法を試してみました。 ただ、結論を先に言うとあまりうまくいきませんでした・・・。一応ダウンロードはできたんですが、イマイチな動きをしています。 サンプルコード全文も記事の後半に載せているので参考になれば幸いです。そしてもっと上手いやり方ご存知の方いらっしゃったらぜひ教えてください^^ ※2021/04/12時点の情報です。 環境 Windows 10 Python 3.8 Selenium 3.141.0 はじめに ログインまでの部分や、webdriverのプロファイル設定に関する部分については、以下記事をご確認ください。 ↑ログインするところまでのサンプルです。(本記事のサンプルコードにもログイン部分あります) ↑サンプルのwebdriverは、Firefoxを使っています。CSVダウンロードするにあたって、Firefoxのプロファイル設定が必要なので、そのあたりを解説しています。 NEOBANKの画面は特殊・・・ これまで楽天銀行や三菱UFJ銀行のCSVダウンロードを試してきましたが、それと比べるとNEOBANKのサイトは特殊です。。。 ちなみにサイト構築にはAngularを使ってるっぽいんですが、そのせいなのかはよく分かってません。 以下、つまづいた点と回避策です。 IDやクラス名などで特定することがほぼできない 単純に使い勝手が独特過ぎて分かりにくいのと、タグの要素も単純にはいきませんでした。例えば他サイトならタグ要素を確定するためにIDやクラス名などで特定できることが多いのですが、NEOBANKの場合ほとんどそれが不可能で、代わりにXPATHかCSSセレクター指定で特定せざるを得ませんでした。 XPATHやCSSセレクターの場合、単純にコードが読みにくくなるのとサイトのちょっとしたデザイン変更が発生した場合うまく動作しなくなるリスクが高くなるんですよね。。 WebDriverWait()による画面表示待機がうまくいかない時がある # ページロード完了まで待機 # ID指定で要素特定する例 WebDriverWait(browser, 10).until( ec.presence_of_element_located((By.ID, "IDの名前を指定")) ) そのため強制的にtime.sleep()でスリープさせることでエラー回避しました。 time.sleep(1) 対象画面まで遷移させる まず、NEOBANK(住信SBIネット銀行)のログイン後のTOP画面から明細ダウンロード画面までどういう経路で遷移できるかを確認してみます。 <画面フロー> TOP画面 入出金明細画面 ← ここでCSVダウンロード 上記フローで目的の画面まで遷移できることが分かりました。では続いて、具体的に各画面ごとの遷移処理を見ていきましょう。 ◆ログイン後のTOP画面 TOP画面から入出金明細画面への遷移は、画面上部にある「入出金明細」をクリックします。こういったヘッダーのメニュー要素でもIDや使えそうなclass指定がなかったので、XPATH指定で要素を特定しました。 # 入出金明細画面へ遷移 browser.find_element_by_css_selector(".m-icon-ps_details").click() ◆入出金明細画面 入出金明細画面の中央部分に、条件を指定するエリアがあるので、ここをSeleniumを使って値を設定していきます。 なお、私の口座の場合「代表口座」と「SBIハイブリッド預金」の2つを登録していますが、ここは皆さんの利用状況次第で変わる部分だと思います。 表示口座の指定方法はつぎのとおりです。 # 表示口座切り替え(代表口座の場合) browser.find_element_by_css_selector(".ng-tns-c4-6 .ui-selectmenu-text").click() browser.find_element_by_xpath("//li[@value='0']").click() # 表示口座切り替え(ハイブリッド口座) browser.find_element_by_css_selector(".ng-tns-c4-6 .ui-selectmenu-text").click() browser.find_element_by_xpath("//li[@value='1']").click() find_element_by_xpath()の引数部分で、valueの値が違っています。 期間を指定する 続いて期間を指定してきます。今回は開始日と終了日を特定したかったのでラジオボタンで「期間指定」を選択し、日付も設定してきます。 # 期間を設定 browser.find_element_by_xpath("//li[5]/label").click() # 開始年月日 browser.find_element_by_xpath("//p[1]/nb-simple-select/span/span[2]").click() browser.find_element_by_xpath("//li[contains(.,'2021年')]").click() browser.find_element_by_xpath("//p[2]/nb-simple-select/span/span[2]").click() browser.find_element_by_xpath("//li[contains(.,'2月')]").click() browser.find_element_by_xpath("//p[3]/nb-simple-select/span/span[2]").click() browser.find_element_by_xpath("//li[contains(.,'1日')]").click() # 終了年 browser.find_element_by_xpath("//div[2]/div[2]/nb-select-ymd/div[2]/div/p/nb-simple-select/span/span[2]").click() # li要素の9個目が、操作中の年(最新の年)とみなすしかなさそう browser.find_element_by_xpath("//div[2]/div[2]/nb-select-ymd/div[2]/div/p/nb-simple-select/div/ul/li[9]").click() # 終了月 browser.find_element_by_xpath("//div[2]/div[2]/nb-select-ymd/div[2]/div/p[2]/nb-simple-select/span/span[2]").click() # li[1]は"--月"で、li[2]が1月、li[3]が2月・・・ browser.find_element_by_xpath("//div[2]/div[2]/nb-select-ymd/div[2]/div/p[2]/nb-simple-select/div/ul/li[3]").click() # 終了日 browser.find_element_by_xpath("//div[2]/div[2]/nb-select-ymd/div[2]/div/p[3]/nb-simple-select/span/span[2]").click() # li[1]は"--月日で、li[2]が1日、li[3]が2日・・・ browser.find_element_by_xpath("//div[2]/div[2]/nb-select-ymd/div[2]/div/p[3]/nb-simple-select/div/ul/li[2]").click() コードを見ていただくと分かるように、開始年月日と終了年月日の指定方法が違っています。なぜか同じ方法だと上手くいきませんでした。試行錯誤の結果、原因特定できなかったため上記コードのような形になっています。また、xpath指定だと設定している年月日が直感的に分かりにくいですね。 表示ボタンをクリックし、CSVダウンロードボタンで実行 期間を設定したら、「表示」ボタンをクリックして明細を表示させます。 # 明細表示 browser.find_element_by_link_text("表示").click() ここではリンクテキストを元に指定してみました。 「表示ボタン」をクリックすると、明細行が表示されます。 あとは「CSVダウンロード」ボタンをクリックすればダウンロード可能になりますが、仮に明細行がない場合は以下のようなエラーメッセージが表示され、「CSVダウンロード」ボタンは表示されません。 このような場合、CSVダウンロードできるかの判断をしてからダウンロード実行するべきなのですが、今回は手を抜いてtry-exceptで囲んで対処しました。 # CSVダウンロード try: browser.find_element_by_link_text("CSVでダウンロード").click() except Exception as e: print("代表口座CSVダウンロードで例外発生") 以上、PythonとSeleniumを使ってNEOBANK(住信SBIネット銀行)の明細取得(CSVダウンロード)する方法でした!いやー大変だった・・・ サンプルコード全文 # # NEOBANK(住信SBIネット銀行)サイトへログイン # import time import json from selenium import webdriver from selenium.webdriver import Firefox, FirefoxOptions from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as ec # 設定ファイルからログイン情報を取得 login_info = json.load(open("login_info.json", "r", encoding="utf-8")) # ログインサイト名 site_name = "bank_neo" # ログイン画面URL url_login = login_info[site_name]["url"] # ユーザー名とパスワードの指定 USER = login_info[site_name]["id"] PASS = login_info[site_name]["pass"] # ダウンロードフォルダ # 相対パス指定はできない模様 # dl_folder = r"..\dl-data" # TODO: ダウンロードフォルダのパスは適宜変更してください dl_folder = r"ダウンロードフォルダのパスを指定" # オプション設定 options = FirefoxOptions() # ヘッドレスモードを有効にする options.add_argument('--headless') # プロファイル設定 fp = webdriver.FirefoxProfile() # ダウンロードフォルダ指定 # 0: デスクトップ、1:システム規定のフォルダ、2:任意の指定フォルダ fp.set_preference("browser.download.folderList", 2) fp.set_preference("browser.download.dir", dl_folder) # ダウンロードマネージャウィンドウを表示させない fp.set_preference("browser.download.manager.showWhenStarting", False) # MIMEタイプを設定 fp.set_preference("browser.helperApps.neverAsk.saveToDisk", "application/octet-stream;text/csv") # Firefoxを起動する browser = Firefox(options=options, firefox_profile=fp) # ログイン画面取得 browser.get(url_login) # 入力 e = browser.find_element_by_id("userName") e.clear() e.send_keys(USER) e = browser.find_element_by_id("loginPwdSet") e.clear() e.send_keys(PASS) # ログイン button = browser.find_element_by_css_selector(".m-btnEm-l > span") button.click() # ページロード完了まで待機 WebDriverWait(browser, 10).until( ec.presence_of_element_located((By.CLASS_NAME, "top-name")) ) # 上記だけだと上手く行かないケースがあるので、念の為スリープ入れる time.sleep(3) # ログインできたか確認(画面キャプチャ取る) # browser.save_screenshot("../screenshots/bank_neo/home.png") # 入出金明細画面へ遷移 browser.find_element_by_css_selector(".m-icon-ps_details").click() time.sleep(1) # 表示口座切り替え(代表口座) browser.find_element_by_css_selector(".ng-tns-c4-6 .ui-selectmenu-text").click() browser.find_element_by_xpath("//li[@value='0']").click() # 期間を設定 browser.find_element_by_xpath("//li[5]/label").click() # 開始年月日 browser.find_element_by_xpath("//p[1]/nb-simple-select/span/span[2]").click() browser.find_element_by_xpath("//li[contains(.,'2021年')]").click() browser.find_element_by_xpath("//p[2]/nb-simple-select/span/span[2]").click() browser.find_element_by_xpath("//li[contains(.,'2月')]").click() browser.find_element_by_xpath("//p[3]/nb-simple-select/span/span[2]").click() browser.find_element_by_xpath("//li[contains(.,'1日')]").click() # 終了年 browser.find_element_by_xpath("//div[2]/div[2]/nb-select-ymd/div[2]/div/p/nb-simple-select/span/span[2]").click() # li要素の9個目が、操作中の年(最新の年)とみなすしかなさそう browser.find_element_by_xpath("//div[2]/div[2]/nb-select-ymd/div[2]/div/p/nb-simple-select/div/ul/li[9]").click() # 終了月 browser.find_element_by_xpath("//div[2]/div[2]/nb-select-ymd/div[2]/div/p[2]/nb-simple-select/span/span[2]").click() # li[1]は"--月"で、li[2]が1月、li[3]が2月・・・ browser.find_element_by_xpath("//div[2]/div[2]/nb-select-ymd/div[2]/div/p[2]/nb-simple-select/div/ul/li[3]").click() # 終了日 browser.find_element_by_xpath("//div[2]/div[2]/nb-select-ymd/div[2]/div/p[3]/nb-simple-select/span/span[2]").click() # li[1]は"--月日で、li[2]が1日、li[3]が2日・・・ browser.find_element_by_xpath("//div[2]/div[2]/nb-select-ymd/div[2]/div/p[3]/nb-simple-select/div/ul/li[2]").click() # 明細表示 browser.find_element_by_link_text("表示").click() time.sleep(1) # CSVダウンロード try: browser.find_element_by_link_text("CSVでダウンロード").click() except Exception as e: print("代表口座CSVダウンロードで例外発生") # 表示口座切り替え(ハイブリッド口座) browser.find_element_by_css_selector(".ng-tns-c4-6 .ui-selectmenu-text").click() browser.find_element_by_xpath("//li[@value='1']").click() # 明細表示 browser.find_element_by_link_text("表示").click() # CSVダウンロード try: browser.find_element_by_link_text("CSVでダウンロード").click() except Exception as e: print("ハイブリッド口座CSVダウンロードで例外発生") # ログアウト # デバッグモードではなく通常実行モードだとなぜかエラーになる # browser.find_element_by_class_name("m-icon-cm_logout").click() # 処理終了 browser.quit()
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

picoCTF 2021 New Caesar Writeup

落ち着いて,粘り強く,1行1行解読すれば,そこまで難しい問題ではなかった。次のCTFでは,こういう取りこぼしをしないようにしたい。Cryptographyというよりpython力が全てなのでGeneral Skillsでいいと思う。 628 solvesと初心者には難問。これが出来れば中級者ってとこでしょうか。 Category: Cryptography Description: We found a brand new type of encryption, can you break the secret code? (Wrap with picoCTF{}) kjlijdliljhdjdhfkfkhhjkkhhkihlhnhghekfhmhjhkhfhekfkkkjkghghjhlhghmhhhfkikfkfhm new_caesar.py Hints 1. How does the cipher work if the alphabet isn't 26 letters? 2. Even though the letters are split up, the same paradigms still apply new_caesar.py import string LOWERCASE_OFFSET = ord("a") ALPHABET = string.ascii_lowercase[:16] def b16_encode(plain): enc = "" for c in plain: binary = "{0:08b}".format(ord(c)) enc += ALPHABET[int(binary[:4], 2)] enc += ALPHABET[int(binary[4:], 2)] return enc def shift(c, k): t1 = ord(c) - LOWERCASE_OFFSET t2 = ord(k) - LOWERCASE_OFFSET return ALPHABET[(t1 + t2) % len(ALPHABET)] flag = "redacted" key = "redacted" assert all([k in ALPHABET for k in key]) assert len(key) == 1 b16 = b16_encode(flag) enc = "" for i, c in enumerate(b16): enc += shift(c, key[i % len(key)]) print(enc) Solution: keyは? ALPHABET = string.ascii_lowercase[:16] assert all([k in ALPHABET for k in key]) assert len(key) == 1 上記から,key は ALPHABET = "abcdefghijklmnop" のいずれか1文字 作戦的には,後で16通り総当たりする b16_encodeとは? def b16_encode(plain): enc = "" for c in plain: binary = "{0:08b}".format(ord(c)) #2進数に enc += ALPHABET[int(binary[:4], 2)] #上位4ビットをインデックスに enc += ALPHABET[int(binary[4:], 2)] #下位4ビットをインデックスに return enc b16 = b16_encode(flag) この処理を通過すると文字長が2倍になり,使われる文字は全てALPHABETの範囲内になる 例えば "p" を b16_encode する "p" は2進数で "01110000" ALPHABET[7] -> "h" ALPHABET[0] -> "a" つまり b16_encode("a") -> "ha" 次に shift def shift(c, k): t1 = ord(c) - LOWERCASE_OFFSET # c が "a" から何文字目か t2 = ord(k) - LOWERCASE_OFFSET # key が "a" から何文字目か return ALPHABET[(t1 + t2) % len(ALPHABET)] # ALPHABETの範囲内で入れ替え for i, c in enumerate(b16): enc += shift(c, key[i % len(key)]) この処理で初めてkeyが使われる 例えば shift("h", "b") でcallしたとする t1 = 104 - 97 = 7 t2 = 98 - 97 = 1 (t1 + t2) % len(ALPHABET) -> 8 ALPHABET[8] -> "i" new_caesar.py の解析がすんだので,ソルバーを作成する solver.py # coding: UTF-8 import string LOWERCASE_OFFSET = ord("a") ALPHABET = string.ascii_lowercase[:16] enc ="kjlijdliljhdjdhfkfkhhjkkhhkihlhnhghekfhmhjhkhfhekfkkkjkghghjhlhghmhhhfkikfkfhm" # 16通り総当たりするための配列を用意する brute16 = [] for i in range(len(ALPHABET)): brute16.append("") # print(brute16) # shiftの逆 for k in range(len(ALPHABET)): for j in enc: # 取り出した enc 中の文字が ALPHABET の何番目か? index = ALPHABET.index(j) # indexは ( ord(c) - LOWERCASE_OFFSET + ord(k) - LOWERCASE_OFFSET ) % len(ALPHABET) # よって index - k + LOWERCASE_OFFSETが求める 値となる # ただkの方が大きいときもあるので,そのときは16加算する(剰余の逆) if(k > index): index += len(ALPHABET) brute16[k] += chr( index - k + LOWERCASE_OFFSET ) # print(brute16) # b16_encodeの逆 for k in range(len(ALPHABET)): flag="" buf = brute16[k] for i in range(0, len(buf), 2): hi = ALPHABET.index(buf[i]) lo = ALPHABET.index(buf[i+1]) flag += chr( ( hi << 4 ) + lo ) print("key= ", end="") print(ALPHABET[k], end="") print(" flag= ", end="") print(flag) 実行結果 >python new_caesar_sol2.py key= a flag= ©¸“¸¹s“u¥§yªw¨{}vt¥|yzut¥ª©¦vy{v|wu¨¥¥| key= b flag= ˜§‚§¨b‚d”–h™f—jlec”khidc”™˜•ehjekfd—””k key= c flag= ‡–q–—QqSƒ…WˆU†Y[TRƒZWXSRƒˆ‡„TWYTZUS†ƒƒZ key= d flag= v…`…†@`BrtFwDuHJCArIFGBArwvsCFHCIDBurrI key= e flag= et_tu?_1ac5f3d7920a85610afeb2572831daa8 key= f flag= TcNcd.N PR$U"S&(!/P'$% /PUTQ!$&!'" SPP' key= g flag= CR=RS=OADBOODC@BOO >32? 1>>,AB,>03 1 key= i flag= !001ûý-/ñ"ÿ óõþü-ôñòýü-"!.þñóþôÿý --ô key= j flag= / / ê ìàîâäíëãàáìëíàâíãîìã ß ÝÑÓÜÚÒßÐÛÚ ÜßÑÜÒÝÛÒ ÈèÊúüÎÿÌýÀÂËÉúÁÎÏÊÉúÿþûËÎÀËÁÌÊýúúÁ key= m flag= íü×üý·×¹éë½î»ì¿±º¸é°½¾¹¸éîí꺽¿º°»¹ìéé° key= n flag= ÜëÆëì¦Æ¨Øڬݪۮ ©§Ø¯¬­¨§ØÝÜÙ©¬®©¯ª¨ÛØد key= o flag= ËÚµÚÛ•µ—Çɛ̙ʝŸ˜–Çž›œ—–ÇÌËȘ›˜ž™—ÊÇÇž key= p flag= ºÉ¤ÉÊ„¤†¶¸Š»ˆ¹ŒŽ‡…¶Š‹†…¶»º·‡ŠŒ‡ˆ†¹¶¶ この中でフラグっぽいのは key= e flag= et_tu?_1ac5f3d7920a85610afeb2572831daa8 new_caesar.pyに上記flagとkeyを設定して,検証 >python new_caesar.py kjlijdliljhdjdhfkfkhhjkkhhkihlhnhghekfhmhjhkhfhekfkkkjkghghjhlhghmhhhfkikfkfhm OK! こういう問題を解くのは,チョー楽しい!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Flaskを使用したLINEログイン連携メモ

Flaskを使用したLINEログイン連携についてメモする。 Google、Facebookで試したログイン連携のLINE版。 大まかな処理の流れ LINEへ認可リクエスト(Authorization Request)を行う。 ユーザー認証/同意を行い、認可レスポンスを受け取る。 認可レスポンスを使ってトークンリクエストを行う。 取得したアクセストークンを使用してユーザープロフィールを取得する。 事前準備 LINE DevelopersコンソールからLINEログインチャネルを作成する。 クライアントID(チャネルID)/クライアントシークレット(チャネルシークレット)を取得する。 コールバックURL(リダイレクトURL)にhttp://localhost:5000/callbackを入力する。 PythonやFlaskのインストールは実施済みであるものとする。 実装 認可リクエスト ~ ユーザープロフィール取得までのコード。 エラーハンドリングなど非対応。 import hashlib from flask import Flask, request, redirect, session import urllib.request import urllib.parse import json import base64 from pprint import pprint import os # クライアント情報 # Channel ID client_id = "<YOUR_CHANNEL_ID>" # Channel Secret client_secret = "<YOUR_CHANNEL_SECRET>" # Callback URL redirect_uri = 'http://localhost:5000/callback' # LINE エンドポイント authorization_url = 'https://access.line.me/dialog/oauth/weblogin' token_url = 'https://api.line.me/v2/oauth/accessToken' user_info_url = 'https://api.line.me/v2/profile' app = Flask(__name__) app.secret_key = 'session_key' # 1.LINEへ認可リクエスト(Authorization Request)を行う。 # ユーザーに認証と認可を要求する:https://developers.line.biz/ja/docs/line-login/integrate-line-login-v2/#making-an-authorization-request @app.route("/login") def login(): # ステート生成 state = hashlib.sha256(os.urandom(32)).hexdigest() session['state'] = state # 認可リクエスト return redirect(authorization_url+'?{}'.format(urllib.parse.urlencode({ 'client_id': client_id, 'redirect_uri': redirect_uri, 'state': state, 'response_type': 'code' }))) # 認可リクエスト受信 → トークンリクエスト → ユーザープロフィールリクエスト @app.route("/callback") def callback(): # 2. ユーザー認証/同意を行い、認可レスポンスを受け取る。 # 認可コードを受け取る:https://developers.line.biz/ja/docs/line-login/integrate-line-login-v2/#receiving-the-authorization-code state = request.args.get('state') if state != session['state']: print("invalid_redirect") code = request.args.get('code') # 3. 認可レスポンスを使ってトークンリクエストを行う。 # ウェブアプリでアクセストークンを取得する:https://developers.line.biz/ja/docs/line-login/integrate-line-login-v2/#get-access-token body = urllib.parse.urlencode({ 'code': code, 'client_id': client_id, 'client_secret': client_secret, 'redirect_uri': redirect_uri, 'grant_type': 'authorization_code' }).encode('utf-8') req, res = '', '' req = urllib.request.Request(token_url) with urllib.request.urlopen(req, data=body) as f: res = f.read() access_token = json.loads(res)['access_token'] # 4. 取得したアクセストークンを使用してユーザープロフィールを取得する。 # ユーザープロフィールを取得する:https://developers.line.biz/ja/docs/line-login/managing-users/#get-profile headers = { 'Authorization': 'Bearer ' + access_token, 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8' } req = urllib.request.Request(user_info_url, headers=headers, method='GET') with urllib.request.urlopen(req) as f: res = f.read() return json.loads(res) if __name__ == "__main__": app.run(debug=True) 参考情報 ウェブアプリにLINEログインを組み込む(LINEログイン v2.0)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

yukarinライブラリをwindowsで使用しようとして四苦八苦した日記のようなもの

初めに これは解説記事ではありません。 やったことを時系列に書いていき、どのようなエラーが出てどう対処したかを書いています。 そのため読みにくいと思いますが、各章の最後にある程度まとめたものを書こうと思います。 環境 windows10 ryzen3700x rtx2070 cuda10 cuda11 anaconda googlecolab 音声データ作成 audacity 3.3はめちゃくちゃ落ちるので 2.4.2を使用した 音声は無料で使おうと思い、ハーメルンの読み上げを使用した。 ランキング一位のものを読み上げた 利用規約は確認中 録音はmoo0音声録音機を使用 audacityで録音することも考えたが、サウンドカードを使用しているため、wasapiではうまく録音ができなかった。 トラックを分離してモノラルにしたの後、新しくトラックをし用意して録音。 ノイズは適当に何もしゃべらず録音しておいてその後エフェクトでなくすのがよい。 プチっという音は消さない。 無音化も最初はやっていたが省略した。 コツとして、一度しゃべり方を聞くのではなく、いきなり録音して失敗したらctrl+zを繰り返すのがよい。 だんだんどこで息継ぎをいれるのかがわかってくる。 例えば接続詞の後や主語の後など。 保存は名前を付けて保存することでいい感じにできる。 フォルダが作成されれるので、それとaupだけで元の音声は必要なくなる。 書きだし方として、最初はそのままwavで出てきたが、 最終的にctlr+bを使用してトラックを分割 inputは24000Hzでないといけないので左下で変更。 target.wavとown.wavを同時に切り取れないので、片方をミュートにしてファイル名プレフィックスの後に番号付けを使用して連番を作った。 またgooglecolabなどとの整合性から、 1.ファイル名はv-から始めること これは後々mean.pnyとvar.npyが出てきたときにv-*というようにファイルを指定するから 2.自分の声と目標の音声は同じ名前にすること。したがってフォルダを分けるとよい。 参考 各種ライブラリのインストール 1.まず新しい環境を作成した。 conda create -n yukaA python anaconda python --version Python 3.8.5 2.condaのアップデート conda update -n base conda 参考 3.pipを最新バージョンに pip install --upgrade pip python -m pip install --upgrade pip しかしなぜか ERROR: Could not install packages due to an EnvironmentError: [WinError 5] アクセスが拒否されました。: 'g:\\anaconda3\\envs\\yukaa\\scripts\\pip.exe' Consider using the `--user` option or check the permissions. こうなってしまったので conda uninstall pip conda install pip condaからもう一度インストールした。 4.管理者でアナコンダプロンプトを使用 うまくいかなかないことが多いのでとりあえず管理者で実行した 5.pyworld これが全然入らない。 scipyを先にinstallしないとinstall出来ない不具合もあるようなので先にinstallしておきます とあるのでしてみたが、 (yukaA) C:\WINDOWS\system32>pip install pyworld Collecting pyworld Using cached pyworld-0.2.12.tar.gz (222 kB) Requirement already satisfied: numpy in g:\anaconda3\envs\yukaa\lib\site-packages (from pyworld) (1.20.2) Collecting cython>=0.24.0 Using cached Cython-0.29.22-py2.py3-none-any.whl (980 kB) Building wheels for collected packages: pyworld Building wheel for pyworld (setup.py) ... error ERROR: Command errored out with exit status 1: command: 'G:\anaconda3\envs\yukaA\python.exe' -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'C:\\Users\\yuki\\AppData\\Local\\Temp\\pip-install-cptybzw4\\pyworld_53a67104522147339b440c0946e12d12\\setup.py'"'"'; __file__='"'"'C:\\Users\\yuki\\AppData\\Local\\Temp\\pip-install-cptybzw4\\pyworld_53a67104522147339b440c0946e12d12\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' bdist_wheel -d 'C:\Users\yuki\AppData\Local\Temp\pip-wheel-6vva5q6d' cwd: C:\Users\yuki\AppData\Local\Temp\pip-install-cptybzw4\pyworld_53a67104522147339b440c0946e12d12\ Complete output (10 lines): running bdist_wheel running build running build_py creating build creating build\lib.win-amd64-3.9 creating build\lib.win-amd64-3.9\pyworld copying pyworld\__init__.py -> build\lib.win-amd64-3.9\pyworld running build_ext building 'pyworld.pyworld' extension error: Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools/ ---------------------------------------- ERROR: Failed building wheel for pyworld Running setup.py clean for pyworld Failed to build pyworld Installing collected packages: cython, pyworld Running setup.py install for pyworld ... error ERROR: Command errored out with exit status 1: command: 'G:\anaconda3\envs\yukaA\python.exe' -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'C:\\Users\\yuki\\AppData\\Local\\Temp\\pip-install-cptybzw4\\pyworld_53a67104522147339b440c0946e12d12\\setup.py'"'"'; __file__='"'"'C:\\Users\\yuki\\AppData\\Local\\Temp\\pip-install-cptybzw4\\pyworld_53a67104522147339b440c0946e12d12\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record 'C:\Users\yuki\AppData\Local\Temp\pip-record-434sndux\install-record.txt' --single-version-externally-managed --compile --install-headers 'G:\anaconda3\envs\yukaA\Include\pyworld' cwd: C:\Users\yuki\AppData\Local\Temp\pip-install-cptybzw4\pyworld_53a67104522147339b440c0946e12d12\ Complete output (11 lines): running install running build running build_py creating build creating build\lib.win-amd64-3.9 creating build\lib.win-amd64-3.9\pyworld copying pyworld\__init__.py -> build\lib.win-amd64-3.9\pyworld running build_ext skipping 'pyworld\pyworld.cpp' Cython extension (up-to-date) building 'pyworld.pyworld' extension error: Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools/ ---------------------------------------- ERROR: Command errored out with exit status 1: 'G:\anaconda3\envs\yukaA\python.exe' -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'C:\\Users\\yuki\\AppData\\Local\\Temp\\pip-install-cptybzw4\\pyworld_53a67104522147339b440c0946e12d12\\setup.py'"'"'; __file__='"'"'C:\\Users\\yuki\\AppData\\Local\\Temp\\pip-install-cptybzw4\\pyworld_53a67104522147339b440c0946e12d12\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record 'C:\Users\yuki\AppData\Local\Temp\pip-record-434sndux\install-record.txt' --single-version-externally-managed --compile --install-headers 'G:\anaconda3\envs\yukaA\Include\pyworld' Check the logs for full command output. となり、インストールできない。 error: Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools/ とあることからhttps://visualstudio.microsoft.com/visual-cpp-build-tools/にアクセス、ダウンロード これを参考にチェックをつける するとpipでうまく入った。 やっとうまくいった 6.pypstk 昨日まで全然できなかったが驚くほどスムーズに入れることができた。 おそらくこれも error: Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools/ これが原因だったのだろう 7.become-yukarin yukarinライブラリのrequirement.txtにあるので入れた pip install git+https://github.com/Hiroshiba/become-yukarin こちらも昨日は全然入らなかったのだが入った。 8.yukarin requirement.txtには書いていないが、必要になったのでこれも入れた pip install git+https://github.com/Hiroshiba/yukarin 9.いざ実行 これを参考に./yukarin/のディレクトリで以下を実行 python scripts/extract_acoustic_feature.py -i ./input_wav/* -o ./input_feature/ Traceback (most recent call last): File "C:\Users\yuki\Downloads\yukarin-master\scripts\extract_acoustic_feature.py", line 13, in <module> from yukarin.acoustic_feature import AcousticFeature File "G:\anaconda3\envs\yukaA\lib\site-packages\yukarin\__init__.py", line 1, in <module> from .acoustic_converter import AcousticConverter File "G:\anaconda3\envs\yukaA\lib\site-packages\yukarin\acoustic_converter.py", line 7, in <module> import librosa File "G:\anaconda3\envs\yukaA\lib\site-packages\librosa\__init__.py", line 12, in <module> from . import core File "G:\anaconda3\envs\yukaA\lib\site-packages\librosa\core\__init__.py", line 109, in <module> from .time_frequency import * # pylint: disable=wildcard-import File "G:\anaconda3\envs\yukaA\lib\site-packages\librosa\core\time_frequency.py", line 10, in <module> from ..util.exceptions import ParameterError File "G:\anaconda3\envs\yukaA\lib\site-packages\librosa\util\__init__.py", line 71, in <module> from . import decorators File "G:\anaconda3\envs\yukaA\lib\site-packages\librosa\util\decorators.py", line 9, in <module> from numba.decorators import jit as optional_jit ModuleNotFoundError: No module named 'numba.decorators' numba.decoratorsがないとのことだが、 によれば5.0から消えてしまったため、ver 0.48が必要な模様 とりあえず一度アンインストールしてから入れなおしてみる pip uninstall numba pip install numba==0.48 Collecting numba==0.48 Downloading numba-0.48.0.tar.gz (2.0 MB) |████████████████████████████████| 2.0 MB 1.1 MB/s Collecting llvmlite<0.32.0,>=0.31.0dev0 Downloading llvmlite-0.31.0.tar.gz (110 kB) |████████████████████████████████| 110 kB 3.2 MB/s Requirement already satisfied: numpy>=1.15 in g:\anaconda3\envs\yukaa\lib\site-packages (from numba==0.48) (1.20.2) Requirement already satisfied: setuptools in g:\anaconda3\envs\yukaa\lib\site-packages (from numba==0.48) (52.0.0.post20210125) Building wheels for collected packages: numba, llvmlite Building wheel for numba (setup.py) ... done Created wheel for numba: filename=numba-0.48.0-cp39-cp39-win_amd64.whl size=2039914 sha256=a80862f10f23c25476374e6a18d50d86681bf730012e5c8ce670466d889f99d7 Stored in directory: c:\users\yuki\appdata\local\pip\cache\wheels\67\f4\34\43855bda1e661dc1afedcb295d313a510239d901336fd636c3 Building wheel for llvmlite (setup.py) ... error ERROR: Command errored out with exit status 1: command: 'G:\anaconda3\envs\yukaA\python.exe' -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'C:\\Users\\yuki\\AppData\\Local\\Temp\\pip-install-3juls8wn\\llvmlite_fb4a6e68607d46eb931588d44c645ef2\\setup.py'"'"'; __file__='"'"'C:\\Users\\yuki\\AppData\\Local\\Temp\\pip-install-3juls8wn\\llvmlite_fb4a6e68607d46eb931588d44c645ef2\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' bdist_wheel -d 'C:\Users\yuki\AppData\Local\Temp\pip-wheel-0lzs0krz' cwd: C:\Users\yuki\AppData\Local\Temp\pip-install-3juls8wn\llvmlite_fb4a6e68607d46eb931588d44c645ef2\ Complete output (24 lines): running bdist_wheel G:\anaconda3\envs\yukaA\python.exe C:\Users\yuki\AppData\Local\Temp\pip-install-3juls8wn\llvmlite_fb4a6e68607d46eb931588d44c645ef2\ffi\build.py Trying generator 'Visual Studio 14 2015 Win64' Traceback (most recent call last): File "C:\Users\yuki\AppData\Local\Temp\pip-install-3juls8wn\llvmlite_fb4a6e68607d46eb931588d44c645ef2\ffi\build.py", line 168, in <module> main() File "C:\Users\yuki\AppData\Local\Temp\pip-install-3juls8wn\llvmlite_fb4a6e68607d46eb931588d44c645ef2\ffi\build.py", line 156, in main main_win32() File "C:\Users\yuki\AppData\Local\Temp\pip-install-3juls8wn\llvmlite_fb4a6e68607d46eb931588d44c645ef2\ffi\build.py", line 88, in main_win32 generator = find_win32_generator() File "C:\Users\yuki\AppData\Local\Temp\pip-install-3juls8wn\llvmlite_fb4a6e68607d46eb931588d44c645ef2\ffi\build.py", line 76, in find_win32_generator try_cmake(cmake_dir, build_dir, generator) File "C:\Users\yuki\AppData\Local\Temp\pip-install-3juls8wn\llvmlite_fb4a6e68607d46eb931588d44c645ef2\ffi\build.py", line 28, in try_cmake subprocess.check_call(['cmake', '-G', generator, cmake_dir]) File "G:\anaconda3\envs\yukaA\lib\subprocess.py", line 368, in check_call retcode = call(*popenargs, **kwargs) File "G:\anaconda3\envs\yukaA\lib\subprocess.py", line 349, in call with Popen(*popenargs, **kwargs) as p: File "G:\anaconda3\envs\yukaA\lib\subprocess.py", line 951, in __init__ self._execute_child(args, executable, preexec_fn, close_fds, File "G:\anaconda3\envs\yukaA\lib\subprocess.py", line 1420, in _execute_child hp, ht, pid, tid = _winapi.CreateProcess(executable, args, FileNotFoundError: [WinError 2] 指定されたファイルが見つかりません。 error: command 'G:\\anaconda3\\envs\\yukaA\\python.exe' failed with exit code 1 ---------------------------------------- ERROR: Failed building wheel for llvmlite Running setup.py clean for llvmlite Successfully built numba Failed to build llvmlite Installing collected packages: llvmlite, numba Attempting uninstall: llvmlite Found existing installation: llvmlite 0.36.0 Uninstalling llvmlite-0.36.0: Successfully uninstalled llvmlite-0.36.0 Running setup.py install for llvmlite ... error ERROR: Command errored out with exit status 1: command: 'G:\anaconda3\envs\yukaA\python.exe' -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'C:\\Users\\yuki\\AppData\\Local\\Temp\\pip-install-3juls8wn\\llvmlite_fb4a6e68607d46eb931588d44c645ef2\\setup.py'"'"'; __file__='"'"'C:\\Users\\yuki\\AppData\\Local\\Temp\\pip-install-3juls8wn\\llvmlite_fb4a6e68607d46eb931588d44c645ef2\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record 'C:\Users\yuki\AppData\Local\Temp\pip-record-zogj41z2\install-record.txt' --single-version-externally-managed --compile --install-headers 'G:\anaconda3\envs\yukaA\Include\llvmlite' cwd: C:\Users\yuki\AppData\Local\Temp\pip-install-3juls8wn\llvmlite_fb4a6e68607d46eb931588d44c645ef2\ Complete output (27 lines): running install running build got version from file C:\Users\yuki\AppData\Local\Temp\pip-install-3juls8wn\llvmlite_fb4a6e68607d46eb931588d44c645ef2\llvmlite/_version.py {'version': '0.31.0', 'full': 'fe7d985f6421d87f613bd414479d29d912771562'} running build_ext G:\anaconda3\envs\yukaA\python.exe C:\Users\yuki\AppData\Local\Temp\pip-install-3juls8wn\llvmlite_fb4a6e68607d46eb931588d44c645ef2\ffi\build.py Trying generator 'Visual Studio 14 2015 Win64' Traceback (most recent call last): File "C:\Users\yuki\AppData\Local\Temp\pip-install-3juls8wn\llvmlite_fb4a6e68607d46eb931588d44c645ef2\ffi\build.py", line 168, in <module> main() File "C:\Users\yuki\AppData\Local\Temp\pip-install-3juls8wn\llvmlite_fb4a6e68607d46eb931588d44c645ef2\ffi\build.py", line 156, in main main_win32() File "C:\Users\yuki\AppData\Local\Temp\pip-install-3juls8wn\llvmlite_fb4a6e68607d46eb931588d44c645ef2\ffi\build.py", line 88, in main_win32 generator = find_win32_generator() File "C:\Users\yuki\AppData\Local\Temp\pip-install-3juls8wn\llvmlite_fb4a6e68607d46eb931588d44c645ef2\ffi\build.py", line 76, in find_win32_generator try_cmake(cmake_dir, build_dir, generator) File "C:\Users\yuki\AppData\Local\Temp\pip-install-3juls8wn\llvmlite_fb4a6e68607d46eb931588d44c645ef2\ffi\build.py", line 28, in try_cmake subprocess.check_call(['cmake', '-G', generator, cmake_dir]) File "G:\anaconda3\envs\yukaA\lib\subprocess.py", line 368, in check_call retcode = call(*popenargs, **kwargs) File "G:\anaconda3\envs\yukaA\lib\subprocess.py", line 349, in call with Popen(*popenargs, **kwargs) as p: File "G:\anaconda3\envs\yukaA\lib\subprocess.py", line 951, in __init__ self._execute_child(args, executable, preexec_fn, close_fds, File "G:\anaconda3\envs\yukaA\lib\subprocess.py", line 1420, in _execute_child hp, ht, pid, tid = _winapi.CreateProcess(executable, args, FileNotFoundError: [WinError 2] 指定されたファイルが見つかりません。 error: command 'G:\\anaconda3\\envs\\yukaA\\python.exe' failed with exit code 1 ---------------------------------------- Rolling back uninstall of llvmlite Moving to g:\anaconda3\envs\yukaa\lib\site-packages\llvmlite-0.36.0.dist-info\ from G:\anaconda3\envs\yukaA\lib\site-packages\~lvmlite-0.36.0.dist-info Moving to g:\anaconda3\envs\yukaa\lib\site-packages\llvmlite\ from G:\anaconda3\envs\yukaA\lib\site-packages\~lvmlite ERROR: Command errored out with exit status 1: 'G:\anaconda3\envs\yukaA\python.exe' -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'C:\\Users\\yuki\\AppData\\Local\\Temp\\pip-install-3juls8wn\\llvmlite_fb4a6e68607d46eb931588d44c645ef2\\setup.py'"'"'; __file__='"'"'C:\\Users\\yuki\\AppData\\Local\\Temp\\pip-install-3juls8wn\\llvmlite_fb4a6e68607d46eb931588d44c645ef2\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record 'C:\Users\yuki\AppData\Local\Temp\pip-record-zogj41z2\install-record.txt' --single-version-externally-managed --compile --install-headers 'G:\anaconda3\envs\yukaA\Include\llvmlite' Check the logs for full command output. これがまた全然入らない。 どうもllvmliteが引っかかる。 原因1 python3.9.2でやっていたが、llvmliteは3.9は未対応らしい 原因2 pip uninstall llvmlite It is a distutils installed project and thus we cannot accurately determine which files belong to it which would lead to only a partial uninstall. このようにllvmliteのバージョンを変えられない これによればcondaとpipの混在が原因らしい。 conda uninstall llvmlite 時間はかかるがアンインストール完了。 その後 pip install llvmlite==0.32.1 とするとはいった 原因3 pip install numba==0.44 失敗 numpyがないとでた。 pip install numpy としても、存在するといわれたので conda install numpy だがnumbaは入らない。 anacondaをし用意していることが原因なのでanacondaの使用をやめる 10.まとめ conda create -n yukaA python==3.8.5 その後 こちらを参考に pip install numpy pip install librosa pip install pysptk pip install pyworld pip install fastdtw pip install matplotlib pip install tqdm pip install world4py pip install git+https://github.com/Hiroshiba/become-yukarin pip install git+https://github.com/Hiroshiba/yukarin pip install numba==0.48 結果うまくいった。 注意として、 pip install numba==0.48 とする前まではnumbaのバージョンが5を超えてしまっていて動かない。 また、llvmliteはnumbaを入れるときに自動的にバージョンが合うためcondaでアンインストールなどはいらなかった。 最終的な環境 pip freeze > req.txt req.txt alembic==1.5.8 appdirs==1.4.4 audioread==2.1.9 become-yukarin @ git+https://github.com/Hiroshiba/become-yukarin@99a4998f4b7b9def2079c42be0edfc70201a1856 certifi==2020.12.5 cffi==1.14.5 chainer==5.4.0 chainerui==0.11.0 chardet==4.0.0 click==7.1.2 cycler==0.10.0 Cython==0.29.22 decorator==5.0.6 fastdtw==0.3.4 filelock==3.0.12 Flask==1.1.2 gevent==21.1.2 greenlet==1.0.0 idna==2.10 itsdangerous==1.1.0 Jinja2==2.11.3 joblib==1.0.1 kiwisolver==1.3.1 librosa==0.6.3 llvmlite==0.31.0 Mako==1.1.4 MarkupSafe==1.1.1 matplotlib==3.4.1 msgpack==1.0.2 numba==0.48.0 numpy==1.20.2 packaging==20.9 Pillow==8.2.0 pooch==1.3.0 protobuf==3.15.8 pycparser==2.20 pyparsing==2.4.7 pysptk==0.1.18 python-dateutil==2.8.1 python-editor==1.0.4 pyworld==0.2.12 requests==2.25.1 resampy==0.2.2 scikit-learn==0.24.1 scipy==1.6.2 six==1.15.0 SoundFile==0.10.3.post1 SQLAlchemy==1.4.6 structlog==21.1.0 tensorflow-gpu-estimator==2.3.0 threadpoolctl==2.1.0 tqdm==4.60.0 typing-extensions==3.7.4.3 urllib3==1.26.4 Werkzeug==1.0.1 wincertstore==0.2 world4py==0.1.1 yukarin @ git+https://github.com/Hiroshiba/yukarin@85f39e21cc8f393396f8c575dec4e297d352dd5a zope.event==4.5.0 zope.interface==5.3.0 yukarinでの特徴量の抽出 フォルダ作成 cd yukarin mkdir input_wav mkdir target_wav mkdir input_feature mkdir target_feature mkdir aligned_indexes メモリエラー  python scripts/extract_acoustic_feature.py -i ./input_wav/* -o ./input_feature/ 失敗。メモリエラー 原因は長い音声ファイルを一個だけおいていたから audacityでトラックを使って分割したものを使用したところ動いた。 inputは24000Hzでないといけないので変更。 参考 また、この際、target.wavとown.wavを同時に切り取れないので、片方をミュートにしてファイル名プレフィックスの後に番号付けを使用して連番を作った。 再び実行 音響特徴量を切り出す python scripts/extract_acoustic_feature.py -i ./input_wav/* -o ./input_feature/ python scripts/extract_acoustic_feature.py -i ./target_wav/* -o ./target_feature/ データを揃える(アライメントする) python scripts/extract_align_indexes.py -i1 ./input_feature/*.npy -i2 ./target_feature/*.npy -o ./aligned_indexes/ 周波数の統計量を求める python scripts/extract_f0_statistics.py -i ./input_feature/*.npy -o ./input_statistics.npy python scripts/extract_f0_statistics.py -i ./target_feature/*.npy -o ./target_statistics.npy python train.py config.json ./model_stage1/ ここまでうまくいった。 まとめ 音声データは細かくしよう yukarin内のtrain.pyを実行(あきらめた) これを参考に 入れていなかったcupyを入れる 私の環境はcuda10とcuda11が入っているが、最新のほうにした またcupyは入れないでおく pip uninstall cupy-cuda110 cudnn問題 実行 python train.py config.json ./model_stage1/ Traceback (most recent call last): File "train.py", line 5, in <module> from chainer import cuda File "G:\anaconda3\envs\yukaA\lib\site-packages\chainer\__init__.py", line 10, in <module> from chainer import dataset # NOQA File "G:\anaconda3\envs\yukaA\lib\site-packages\chainer\dataset\__init__.py", line 2, in <module> from chainer.dataset.convert import concat_examples # NOQA File "G:\anaconda3\envs\yukaA\lib\site-packages\chainer\dataset\convert.py", line 6, in <module> from chainer import backend File "G:\anaconda3\envs\yukaA\lib\site-packages\chainer\backend.py", line 4, in <module> from chainer.backends import cuda File "G:\anaconda3\envs\yukaA\lib\site-packages\chainer\backends\cuda.py", line 608, in <module> _cudnn_version = cuda.cudnn.getVersion() if cudnn_enabled else -1 File "G:\anaconda3\envs\yukaA\lib\site-packages\cupy\cuda\__init__.py", line 77, in __getattr__ raise AttributeError( AttributeError: module 'cupy.cuda' has no attribute 'cudnn' バージョンが悪いか pip uninstall cupy-cuda110 pip install cupy-cuda100 としてみたが動かない AttributeError: module 'cupy.cuda' has no attribute 'cudnn' 動かない pip install cupy==5.4.0 としたが、まず入れるのに時間がとてもかかったうえ、動かない。 pip list cupy 5.4.0 cupy-cuda100 8.6.0 原因としてverは8.6.0だからと考えた。 requirement.txtにはバージョン6未満と書かれているし、 chainer自体5.4.0だから。 pip install cupy==5.4.0 だがそんなバージョン存在しないと出てきた。 これを見る限りcupy-cuda110には5.4がないが、cupy-cuda100には5.4がある。 だが入らない。 pip install cupy-cuda100==5.4.0 ERROR: Could not find a version that satisfies the requirement cupy-cuda100==5.4.0 ERROR: No matching distribution found for cupy-cuda100==5.4.0 を見るとpython3.8に対応していなかった 3.7の環境を作り直していざもう一度 conda create -n yukaB python==3.7 pip install cupy-cuda100==5.4.0 はいった そして問題は解決した config.jsonが動かない python train.py config.json ./model_stage1/ Traceback (most recent call last): File "train.py", line 23, in <module> config = create_from_json(arguments.config_json_path) File "C:\Users\yuki\Downloads\become-yukarin-master\become_yukarin\config\config.py", line 86, in create_from_json d = json.load(open(s)) File "G:\anaconda3\envs\yukaA\lib\json\__init__.py", line 293, in load return loads(fp.read(), File "G:\anaconda3\envs\yukaA\lib\json\__init__.py", line 357, in loads return _default_decoder.decode(s) File "G:\anaconda3\envs\yukaA\lib\json\decoder.py", line 337, in decode obj, end = self.raw_decode(s, idx=_w(s, 0).end()) File "G:\anaconda3\envs\yukaA\lib\json\decoder.py", line 355, in raw_decode raise JSONDecodeError("Expecting value", s, err.value) from None json.decoder.JSONDecodeError: Expecting value: line 7 column 19 (char 85) 思い切り勘違いをしていた。 become-yukarinのconfigを使用してyukarinを動かしていたことが原因だった ちゃんとyukarin内のconfig.jsonを書き換えて使用したところ動いた。 足りないパッケージ 改めて事項するとtb_chainerがない pip install git+https://github.com/neka-nat/tensorboard-chainer これもやっておく become-yukarin内のsample_config.jsonをconfig.jsonに変更 中身を変えてyukari/に置いた。 メモリエラー  python train.py config.json ./model_stage1/ MemoryError G:\anaconda3\envs\yukaA\lib\site-packages\chainer\iterators\multiprocess_iterator.py:25: TimeoutWarning: Stalled dataset is detected. See the documentation of MultiprocessIterator for common causes and workarounds: https://docs.chainer.org/en/stable/reference/generated/chainer.iterators.MultiprocessIterator.html warnings.warn( メモリエラーになった とりあえずrequirementにあったので  pip install tensorflow-gpu 2.4.1が入ったが特に変化なし config.json内の "train_crop_size": 512, を "train_crop_size": 64, としたところMemoryErrorは出なくなった Output sizes should be positive しかし実行すると assert all(out > 0 for out in outs), 'Output sizes should be positive.' AssertionError: Output sizes should be positive. これが出てきて永遠に進まない。 これは原因がさっぱりわからなかった。 なのでyukarinを実行することをあきらめた。 まとめ pythonは3.7 cupy-cuda100は5.4 conda create -n yukaB python==3.7 pip install cupy-cuda100==5.4.0 足りないものはインストール pip install git+https://github.com/neka-nat/tensorboard-chainer メモリが問題になったらconfig.json内の "train_crop_size": 512, を変更 become-yukarinを試す become-yukarinに移行することにした。 ディレクトリの作成 cd become-yukarin mkdir input_wav mkdir target_wav mkdir input_feature mkdir target_feature model_stage1 各種wavも移した 特徴量の抽出 cd become-yukarin python scripts/extract_acoustic_feature.py -i1 input_wav -i2 target_wav -o1 input_feature -o2 target_feature うまくいった become-yukarinでのtrain.py config.json become-yukarinのrecipe内のconfig.jsonをもとに編集して、become-yukarin直下に移動した。 windows環境なのでconfig.jsonのパスから先頭の/をなくした "/target_feature/v-*.npy", これを "target_feature/v-*.npy", こうした また私の使うrtx2070では余裕があったのでbatchsizeを大きくした。 また自分なりに理解した内容 config.py { "dataset": { "features": [ "f0", "mfcc" ], "input_glob": "input_feature/v-*.npy",#v-から始まる自分の音声の特徴量。v-と指定するのはmean.npyとvar.npyが存在するから "input_global_noise": 0.01, "input_local_noise": 0.01, "input_mean_path": "input_feature/mean.npy", "input_var_path": "input_feature/var.npy", "num_test": 1, "seed": 0, "target_glob": "target_feature/v-*.npy",#v-から始まる目標の音声の特徴量。v-と指定するのはmean.npyとvar.npyが存在するから "target_global_noise": 0.01, "target_local_noise": 0.01, "target_mean_path": "target_feature/mean.npy", "target_var_path": "target_feature/var.npy", "train_crop_size": 512 }, "loss": { "adversarial": 1, "mse": 100 }, "model": {#ここら辺は学習のモデルの構造を指定しているから、いじると汎用性がなくなる可能性あり。 "in_channels": 10, "out_channels": 10, "generator_base_channels": 64, "generator_extensive_layers": 8, "discriminator_base_channels": 32, "discriminator_extensive_layers": 5, "weak_discriminator": false }, "project": { "name": "", "tags": [] }, "train": { "batchsize": 8,#学習時のバッチサイズ "gpu": 0,#0でgpu, "log_iteration": 250,#logにaccやlossを保存する頻度 "snapshot_iteration": 5000#predictor_数字.npzの保存する頻度 } } pickle問題 まずtrainを実行 python train.py config.json model_stage1 AttributeError: Can't pickle local object 'create.<locals>.<lambda>' 動かなかった 先人の知恵を借りた。 pickleのエラーに悩まされました。 回避方法を教えていただきました。 C:\Usersユーザ名\Anaconda3\pkgs\python-3.6.5-h0c2934d_0\Lib\multiprocessing\http://reduction.py/ の15行目にある import pickleを import dill as pickleに変更 dillはpipなどからインストールしてください だそうです。Python本体のマルチスレッド部分のpickleを互換ライブラリのdillで置き換える方法になります。 これで学習ができます。 おそらくこのサイトを見たのだろう まずpythonのバージョンを確認。 python --version 3.7.0 その後対応するフォルダのpyの中身を変更 C:\Usersユーザ名\Anaconda3\pkgs\python-3.7.0-h0c2934d_0\Lib\multiprocessing\http://reduction.py/ ここの先頭のimportの部分を #import pickle import dill as pickle に変更 pip install dill import dill as pickle しかしdillをインストールしていなかったため、 ImportError: cannot import name 'reduce_socket' from 'multiprocessing.reduction' (G:\anaconda3\envs\yukaB\lib\multiprocessing\reduction.py) と出てしまい、 pip listさえも動かなくなった import pickleに直してから pip install dill 改めて pip install dill import dill as pickle に変更したところ動いた。 メモリエラー  再び実行したところメモリエラーが起きた。 config.json内の "generator_base_channels": 64, を "generator_base_channels": 8, に変更した。 scypi問題 AttributeError: module 'scipy' has no attribute '_lib' pip だと最新になっていたので condaがなぜか原因になっていた。 conda install scipy として最新にした。 numpyの問題 実行すると python train.py config.json model_stage1 Traceback (most recent call last): File "train.py", line 12, in <module> from become_yukarin.config.config import create_from_json File "C:\Users\yuki\Downloads\become-yukarin\become_yukarin\__init__.py", line 2, in <module> from . import dataset File "C:\Users\yuki\Downloads\become-yukarin\become_yukarin\dataset\__init__.py", line 1, in <module> from . import dataset File "C:\Users\yuki\Downloads\become-yukarin\become_yukarin\dataset\dataset.py", line 15, in <module> import pysptk File "G:\anaconda3\envs\yukaB\lib\site-packages\pysptk\__init__.py", line 41, in <module> from .sptk import * # pylint: disable=wildcard-import File "G:\anaconda3\envs\yukaB\lib\site-packages\pysptk\sptk.py", line 147, in <module> from . import _sptk File "__init__.pxd", line 242, in init pysptk._sptk ValueError: numpy.ndarray size changed, may indicate binary incompatibility. Expected 88 from C header, got 80 from PyObject どうも調べるとnumpyのバージョンが2.0未満だと起きるらしい。 pip install numpy==1.19.5 これだと動かないが、 pip install numpy==1.20 とすると動いた。 実行 上記を経てやっと動いた。 しかし何も画面に出てこないので失敗したかと思ったが、実行はされているみたいで、 まとめ このように変更 pip install dill import dill as pickle ''' numpyは1.20以降に pip install numpy==1.20 ``` scipyはcondaのほうを最新に conda install scipy 最終的な環境 absl-py==0.12.0 alembic==1.5.8 appdirs==1.4.4 audioread==2.1.9 become-yukarin @ git+https://github.com/Hiroshiba/become-yukarin@99a4998f4b7b9def2079c42be0edfc70201a1856 bleach==3.3.0 cachetools==4.2.1 certifi==2020.12.5 cffi==1.14.5 chainer==5.4.0 chainerui==0.11.0 chardet==4.0.0 click==7.1.2 colorama==0.4.4 cupy-cuda100==5.4.0 cycler==0.10.0 Cython==0.29.22 decorator==5.0.6 dill==0.3.0 docutils==0.17 fastdtw==0.3.4 fastrlock==0.6 filelock==3.0.12 Flask==1.1.2 gevent==21.1.2 google-auth==1.28.1 google-auth-oauthlib==0.4.4 greenlet==1.0.0 grpcio==1.37.0 idna==2.10 importlib-metadata==3.10.0 itsdangerous==1.1.0 Jinja2==2.11.3 joblib==1.0.1 keyring==23.0.1 kiwisolver==1.3.1 librosa==0.6.3 llvmlite==0.31.0 Mako==1.1.4 Markdown==3.3.4 MarkupSafe==1.1.1 matplotlib==3.4.1 msgpack==1.0.2 numba==0.48.0 numpy==1.20.2 oauthlib==3.1.0 packaging==20.9 Pillow==8.2.0 pkginfo==1.7.0 pooch==1.3.0 protobuf==3.15.8 pyasn1==0.4.8 pyasn1-modules==0.2.8 pycparser==2.20 Pygments==2.8.1 pyparsing==2.4.7 pysptk==0.1.18 python-dateutil==2.8.1 python-editor==1.0.4 pywin32-ctypes==0.2.0 pyworld==0.2.12 readme-renderer==29.0 requests==2.25.1 requests-oauthlib==1.3.0 requests-toolbelt==0.9.1 resampy==0.2.2 rfc3986==1.4.0 rsa==4.7.2 scikit-learn==0.24.1 scipy==1.6.2 six==1.15.0 SoundFile==0.10.3.post1 SQLAlchemy==1.4.7 structlog==21.1.0 tensorboard==2.4.1 tensorboard-chainer @ git+https://github.com/neka-nat/tensorboard-chainer@e537dc0712fb282b247986aea6105ded7b3beb59 tensorboard-plugin-wit==1.8.0 threadpoolctl==2.1.0 tqdm==4.60.0 twine==3.4.1 typing-extensions==3.7.4.3 urllib3==1.26.4 webencodings==0.5.1 Werkzeug==1.0.1 wincertstore==0.2 world4py==0.1.1 yukarin @ git+https://github.com/Hiroshiba/yukarin@85f39e21cc8f393396f8c575dec4e297d352dd5a zipp==3.4.1 zope.event==4.5.0 zope.interface==5.3.0 become-yukarin第一段階学習後のvoice_conversion_test.pyをテストしてみる コマンドライン因数 voice_conversion_test.pyを実行したいのだが、コマンドラインの因数がさっぱりわからない。 中身をのぞくと、 voice_conversion_test.py parser = argparse.ArgumentParser() parser.add_argument('model_names', nargs='+') parser.add_argument('-md', '--model_directory', type=Path, default=Path('/mnt/dwango/hiroshiba/become-yukarin/')) parser.add_argument('-iwd', '--input_wave_directory', type=Path, default=Path('/mnt/dwango/hiroshiba/become-yukarin/dataset/hiho-wave/hiho-pause-atr503-subset/')) parser.add_argument('-it', '--iteration', type=int) parser.add_argument('-g', '--gpu', type=int) args = parser.parse_args() とあるので、 なし  'model_names' '-md', '--model_directory' '-iwd', '--input_wave_directory' '-it', '--iteration' '-g', '--gpu' となっていることが分かったが、やっぱりよくわからなかったので、さらに調べたところ、 voice_conversion_test.py for model_name in args.model_names: base_model = model_directory / model_name config = create_config(base_model / 'config.json') とあるから、 model_nameは学習済みのnpyとconfig.jsonがあるフォルダ model_directoryはmodel_nameがあるディレクトリまでのパス。 今回はカレントディレクトリだったので、.とした。 iwdは自分の24000Hz16bitののwavaがあるフォルダ。ここからランダムで数個変換するらしい。 voice_conversion_test.py if it is not None: model_path = base_model / 'predictor_{}.npz'.format(it) else: model_paths = base_model.glob('predictor_*.npz') model_path = list(sorted(model_paths, key=extract_number))[-1] とあるから、itは学習済みのnpyのうちどのiterationのものを使用するか 書かなければ最新のものが使用されるっぽい -gは voice_conversion_test.py if gpu is None: pool = multiprocessing.Pool() pool.map(process_partial, paths) else: list(map(process_partial, paths)) とあるから、おそらく0で使用、何も書かなければcpu フォルダ さらに、 voice_conversion_test.py paths_test = list(Path('./test_data/').glob('*.wav')) output = Path('./output').absolute() / base_model.name output.mkdir(exist_ok=True) とあることから、 mkdir output mkdir test_data も作っておく 実行したのがこちら python scripts/voice_conversion_test.py model_stage1 -iwd input_wav -md . -it 80000 -g 0 numpy問題再び 実行すると DeprecationWarning: `np.float` is a deprecated alias for the builtin `float`. To silence this warning, use `float` by itself. Doing this will not modify any behavior and is safe. If you specifically wanted the numpy scalar type, use `np.float64` here. によればnumpy>=1.20になると起きてしまうらしい。 バージョンを落とすと pip install numpy==1.19 ValueError: numpy.ndarray size changed, may indicate binary incompatibility. Expected 88 from C header, got 80 from PyObject やはりこの問題にたどり着いてしまう。 1.17や最新の1.20.2をい試してもダメ。 これを参考に pip install numpy==1.19.5 --no-binary :all: としてみたが、ダメ。 つまりnumpyが 2.0~なら DeprecationWarning: `np.float` is a deprecated alias for the builtin `float`. To silence this warning, use `float` by itself. Doing this will not modify any behavior and is safe. If you specifically wanted the numpy scalar type, use `np.float64` here. が出てきてしまい、 ~2.0だと ValueError: numpy.ndarray size changed, may indicate binary incompatibility. Expected 88 from C header, got 80 from PyObject こうなってしまう これを参考に pip install numpy==1.19.5 --no-cache-dir --no-binary :all: 無理 詰んだ。 あきらめて numpy==1.20の環境でコマンドライン因数の-g 0を削除 するとcpuをフルに使って実行することができた。 しかしずっとループしており、止まらない。 outputに変換後のwavが出てきたが再生できないので失敗かと思えば、vlcで聞くことができた。 これはcolabにも注意として載っている。 生成したwavファイルは VLCなどで、再生してください。MSのメディアプレーヤーでは再生できません。 まとめ numpyは1.20以降 -gは書かず、cpuを使用する。 vlcで聞く googlecolabへ移行 先日以下の記事を見つけた。 この通りやってみたが、うまくいかなかったのでwindowsで実行することにしたのだが、 windowsで詰んでしまったのでもう一度使用することにした。 pipについて pip install cupy はいらない。 一通りpipでインストールした後に、 !python -c 'import chainer; chainer.print_runtime_info()' とすれば Platform: Linux-4.19.112+-x86_64-with-Ubuntu-18.04-bionic Chainer: 5.4.0 NumPy: 1.16.2 CuPy: CuPy Version : 5.4.0 CUDA Root : /usr/local/cuda CUDA Build Version : 10010 CUDA Driver Version : 11020 CUDA Runtime Version : 10010 cuDNN Build Version : 7500 cuDNN Version : 7500 NCCL Build Version : 2402 NCCL Runtime Version : 2402 iDeep: 2.0.0.post3 となり、cupyがもともと入っていることがわかる。 ディレクトリについて ディレクトリだが、説明があまりない ローカルでdeep_yukarin以下を作ってからgoogledriveにアップロードするのがよい。 これを参考にだが、 #ここ追加 mkdir deep_yukarin cd deep_yukarin mkdir dat mkdir dat/1st_models_by mkdir dat/2nd_models_by mkdir dat/1st_models_y mkdir dat/1st_models_by/yukari mkdir dat/1st_models_by/yukari/npy_pair #ここ追加 mkdir dat/1st_models_by/yukari/voice_pair mkdir dat/2nd_models_by/yukari mkdir dat/1st_models_y/yukari mkdir dat/1st_models_y/yukari/aligned_indexes mkdir dat/1st_models_y/yukari/aligned_wav mkdir dat/1st_models_y/yukari/statistics mkdir dat/1st_models_y/yukari/npy_pair mkdir dat/input mkdir dat/output mkdir dat/voice_src mkdir dat/voice_src/voice_24000 mkdir dat/voice_src/voice_44100 mkdir dat/voice_src/voice_24000/yukari_pair mkdir dat/voice_src/voice_24000/yukari_pair/own mkdir dat/voice_src/voice_24000/yukari_pair/target mkdir dat/voice_src/voice_24000/yukari_single mkdir dat/voice_src/voice_44100/yukari_pair mkdir dat/voice_src/voice_44100/yukari_pair/own mkdir dat/voice_src/voice_44100/yukari_pair/target mkdir dat/voice_src/voice_44100/yukari_single これをコマンドラインで実行するのをお勧めする。(linuxの場合) windowsはこちら #ここ追加 mkdir deep_yukarin cd deep_yukarin mkdir dat mkdir dat\1st_models_by mkdir dat\2nd_models_by mkdir dat\1st_models_y mkdir dat\1st_models_by\yukari mkdir dat\1st_models_by\yukari\npy_pair #ここ追加 mkdir dat\1st_models_by\yukari\voice_pair mkdir dat\2nd_models_by\yukari mkdir dat\1st_models_y\yukari mkdir dat\1st_models_y\yukari\aligned_indexes mkdir dat\1st_models_y\yukari\aligned_wav mkdir dat\1st_models_y\yukari\statistics mkdir dat\1st_models_y\yukari\npy_pair mkdir dat\input mkdir dat\output mkdir dat\voice_src mkdir dat\voice_src\voice_24000 mkdir dat\voice_src\voice_44100 mkdir dat\voice_src\voice_24000\yukari_pair mkdir dat\voice_src\voice_24000\yukari_pair\own mkdir dat\voice_src\voice_24000\yukari_pair\target mkdir dat\voice_src\voice_24000\yukari_single mkdir dat\voice_src\voice_44100\yukari_pair mkdir dat\voice_src\voice_44100\yukari_pair\own mkdir dat\voice_src\voice_44100\yukari_pair\target mkdir dat\voice_src\voice_44100\yukari_single やりたいこと predictoerだけ保存しているからdiscもnpy保存して、とってくるようにしたい windowsでbecome-yukarinの2段階特徴量抽出(失敗、colabに移行) googlecolabでは問題なく実行可能。 しかし遅いアンドnpyのサイズが大きくて圧迫しているので 再びwindowsで特徴量抽出 python scripts/extract_spectrogram_pair.py -i single -o a {'alpha': 0.466, 'enable_overwrite': False, 'f0_estimating_method': 'harvest', 'frame_period': 5, 'input_directory': WindowsPath('single'), 'order': 8, 'output_directory': WindowsPath('single'), 'pad_second': 0.0, 'sample_rate': 24000, 'top_db': None} 0%| | 0/104 [00:02<?, ?it/s] multiprocessing.pool.RemoteTraceback: """ Traceback (most recent call last): File "G:\anaconda3\envs\yukaB\lib\multiprocessing\pool.py", line 121, in worker result = (True, func(*args, **kwds)) File "scripts/extract_spectrogram_pair.py", line 38, in generate_file out = Path(arguments.output_directory, path.stem + '.npy') NameError: name 'Path' is not defined """ The above exception was the direct cause of the following exception: Traceback (most recent call last): File "scripts/extract_spectrogram_pair.py", line 85, in <module> main() File "scripts/extract_spectrogram_pair.py", line 81, in main list(tqdm(pool.imap(generate_file, paths), total=len(paths))) File "G:\anaconda3\envs\yukaB\lib\site-packages\tqdm\std.py", line 1178, in __iter__ for obj in iterable: File "G:\anaconda3\envs\yukaB\lib\multiprocessing\pool.py", line 748, in next raise value NameError: name 'Path' is not defined 動かない pip install pathlib pip install argparse 動かない なぜかimportしているのにPathが使えなかったり、定義しているのにargumentsがないといわれたりと意味不明 ならばと extract_spectrogram_pair.py pool = multiprocessing.Pool() list(tqdm(pool.imap(generate_file, paths), total=len(paths))) ここを extract_spectrogram_pair.py for tmp in paths: generate_file(tmp) にしたところ動いた(遅いが) 一段階の特徴量抽出のextract_acoustic_feature.pyではpoolで並列処理する部分は、 extract_acoustic_feature.py pool.starmap(generate_feature, zip(paths1, paths2), chunksize=16) となっているため、imapが悪さをしている気がした。 と思ったが何をしてもやはりPathの部分が存在しないことになってしまう。 あきらめた。 become-yukarin二段階学習のtrain_sr.py これは何を学習するのかよくわからなかったのだが、 これだったり これを見る限りひたすら目標の音声だけを用意すれば学習するらしい。 python train_sr.py config_sr.json model_stage2 config_sr.jsonにおいて、 "batchsize": 4 がrtx2070の8gbのgpuメモリでは限界 "log_iteration": 50, "snapshot_iteration": 250 思った以上に時間がかかるので以上に変更 cudaはmaxになった become-yukarinの二段階学習後にsuper_resolution_test.pyで試してみる コマンドライン因数は基本的に第一段階と同じ test_data_srを作り、そこに1段階変換後のものを置く outputにmodenameが作られてそこに出力されるみたい python scripts/super_resolution_test.py model_stage2 -md . -iwd single if __name__ == '__main__': freeze_support() ... The "freeze_support()" line can be omitted if the program is not going to be frozen to produce an executable. Traceback (most recent call last): File "<string>", line 1, in <module> File "G:\anaconda3\envs\yukaB\lib\multiprocessing\spawn.py", line 105, in spawn_main exitcode = _main(fd) File "G:\anaconda3\envs\yukaB\lib\multiprocessing\spawn.py", line 114, in _main prepare(preparation_data) File "G:\anaconda3\envs\yukaB\lib\multiprocessing\spawn.py", line 225, in prepare _fixup_main_from_path(data['init_main_from_path']) File "G:\anaconda3\envs\yukaB\lib\multiprocessing\spawn.py", line 277, in _fixup_main_from_path run_name="__mp_main__") File "G:\anaconda3\envs\yukaB\lib\runpy.py", line 263, in run_path pkg_name=pkg_name, script_name=fname) File "G:\anaconda3\envs\yukaB\lib\runpy.py", line 96, in _run_module_code mod_name, mod_spec, pkg_name, script_name) File "G:\anaconda3\envs\yukaB\lib\runpy.py", line 85, in _run_code exec(code, run_globals) File "C:\Users\yuki\Downloads\become-yukarin\scripts\super_resolution_test.py", line 83, in <module> pool = multiprocessing.Pool() File "G:\anaconda3\envs\yukaB\lib\multiprocessing\context.py", line 119, in Pool context=self.get_context()) File "G:\anaconda3\envs\yukaB\lib\multiprocessing\pool.py", line 176, in __init__ self._repopulate_pool() File "G:\anaconda3\envs\yukaB\lib\multiprocessing\pool.py", line 241, in _repopulate_pool w.start() File "G:\anaconda3\envs\yukaB\lib\multiprocessing\process.py", line 112, in start self._popen = self._Popen(self) File "G:\anaconda3\envs\yukaB\lib\multiprocessing\context.py", line 322, in _Popen return Popen(process_obj) File "G:\anaconda3\envs\yukaB\lib\multiprocessing\popen_spawn_win32.py", line 33, in __init__ prep_data = spawn.get_preparation_data(process_obj._name) File "G:\anaconda3\envs\yukaB\lib\multiprocessing\spawn.py", line 143, in get_preparation_data _check_not_importing_main() File "G:\anaconda3\envs\yukaB\lib\multiprocessing\spawn.py", line 136, in _check_not_importing_main is not going to be frozen to produce an executable.''') RuntimeError: An attempt has been made to start a new process before the current process has finished its bootstrapping phase. This probably means that you are not using fork to start your child processes and you have forgotten to use the proper idiom in the main module: こんなのがたくさんループして実行不可能 gpuを-1にしてcpuを使おうとしても実行不可能 あきらめてgooglecolabで実行した。 もちろん問題なし googlecolabを参考に環境を作り直す windowsで試すことをあきらめきれず googleの環境をそっくりそのままwindowsすべてに入れようとした。 googlevolab上で、 !pip freeze > yuka.txt !python --verison 3.7.10 conda create -n googleyuka pip python==3.7.10 conda activate googleyuka pip install -r yuka.txt その結果がこちら absl-py==0.12.0 alabaster==0.7.12 albumentations==0.1.12 alembic==1.5.8 altair==4.1.0 appdirs==1.4.4 APScheduler==3.7.0 argon2-cffi==20.1.0 astor==0.8.1 astropy==4.2 astunparse==1.6.3 async-generator==1.10 atari-py==0.2.6 atomicwrites==1.4.0 attrs==20.3.0 audioread==2.1.9 autograd==1.3 Babel==2.9.0 backcall==0.2.0 beautifulsoup4==4.6.3 bleach==3.3.0 blis==0.4.1 bokeh==2.3.0 Bottleneck==1.3.2 branca==0.4.2 bs4==0.0.1 CacheControl==0.12.6 cachetools==4.2.1 catalogue==1.0.0 certifi==2020.12.5 cffi==1.14.5 chainer==5.4.0 chainerui==0.3.0 chardet==3.0.4 click==7.1.2 cloudpickle==1.3.0 cmake==3.12.0 cmdstanpy==0.9.5 colorcet==2.0.6 colorlover==0.3.0 community==1.0.0b1 contextlib2==0.5.5 convertdate==2.3.2 coverage==3.7.1 coveralls==0.5 crcmod==1.7 cufflinks==0.17.3 cupy-cuda100==5.4.0 cvxopt==1.2.6 cvxpy==1.0.31 cycler==0.10.0 cymem==2.0.5 Cython==0.29.22 daft==0.0.4 dask==2.12.0 datascience==0.10.6 debugpy==1.0.0 decorator==4.4.2 defusedxml==0.7.1 descartes==1.1.0 dill==0.3.3 distributed==1.25.3 dlib==19.18.0 dm-tree==0.1.5 docopt==0.6.2 docutils==0.16 dopamine-rl==1.0.5 earthengine-api==0.1.258 easydict==1.9 ecos==2.0.7.post1 editdistance==0.5.3 en-core-web-sm==2.2.5 entrypoints==0.3 ephem==3.7.7.1 et-xmlfile==1.0.1 fa2==0.3.5 fancyimpute==0.4.3 fastai==1.0.61 fastdtw==0.3.4 fastprogress==1.0.0 fastrlock==0.6 fbprophet==0.7.1 feather-format==0.4.1 filelock==3.0.12 firebase-admin==4.4.0 fix-yahoo-finance==0.0.22 Flask==1.1.2 flatbuffers==1.12 folium==0.2.1 future==0.16.0 gast==0.3.3 GDAL==2.2.2 gdown==3.6.4 gensim==3.6.0 geographiclib==1.50 geopy==1.17.0 gin-config==0.4.0 glob2==0.7 google==2.0.3 google-api-core==1.26.2 google-api-python-client==1.12.8 google-auth==1.28.0 google-auth-httplib2==0.0.4 google-auth-oauthlib==0.4.3 google-cloud-bigquery==1.21.0 google-cloud-bigquery-storage==1.1.0 google-cloud-core==1.0.3 google-cloud-datastore==1.8.0 google-cloud-firestore==1.7.0 google-cloud-language==1.2.0 google-cloud-storage==1.18.1 google-cloud-translate==1.5.0 google-colab==1.0.0 google-pasta==0.2.0 google-resumable-media==0.4.1 googleapis-common-protos==1.53.0 googledrivedownloader==0.4 graphviz==0.10.1 greenlet==1.0.0 grpcio==1.32.0 gspread==3.0.1 gspread-dataframe==3.0.8 gym==0.17.3 h5py==2.10.0 HeapDict==1.0.1 hijri-converter==2.1.1 holidays==0.10.5.2 holoviews==1.14.2 html5lib==1.0.1 httpimport==0.5.18 httplib2==0.17.4 httplib2shim==0.0.3 humanize==0.5.1 hyperopt==0.1.2 ideep4py==2.0.0.post3 idna==2.10 imageio==2.4.1 imagesize==1.2.0 imbalanced-learn==0.4.3 imblearn==0.0 imgaug==0.2.5 importlib-metadata==3.8.1 importlib-resources==5.1.2 imutils==0.5.4 inflect==2.1.0 iniconfig==1.1.1 intel-openmp==2021.2.0 intervaltree==2.1.0 ipykernel==4.10.1 ipython==5.5.0 ipython-genutils==0.2.0 ipython-sql==0.3.9 ipywidgets==7.6.3 itsdangerous==1.1.0 jax==0.2.11 jaxlib==0.1.64+cuda110 jdcal==1.4.1 jedi==0.18.0 jieba==0.42.1 Jinja2==2.11.3 joblib==1.0.1 jpeg4py==0.1.4 jsonschema==2.6.0 jupyter==1.0.0 jupyter-client==5.3.5 jupyter-console==5.2.0 jupyter-core==4.7.1 jupyterlab-pygments==0.1.2 jupyterlab-widgets==1.0.0 kaggle==1.5.12 kapre==0.1.3.1 Keras==2.4.3 Keras-Preprocessing==1.1.2 keras-vis==0.4.1 kiwisolver==1.3.1 knnimpute==0.1.0 korean-lunar-calendar==0.2.1 librosa==0.6.3 lightgbm==2.2.3 llvmlite==0.32.1 lmdb==0.99 LunarCalendar==0.0.9 lxml==4.2.6 Mako==1.1.4 Markdown==3.3.4 MarkupSafe==1.1.1 matplotlib==3.2.2 matplotlib-venn==0.11.6 missingno==0.4.2 mistune==0.8.4 mizani==0.6.0 mkl==2019.0 mlxtend==0.14.0 more-itertools==8.7.0 moviepy==0.2.3.5 mpmath==1.2.1 msgpack==1.0.2 multiprocess==0.70.11.1 multitasking==0.0.9 murmurhash==1.0.5 music21==5.5.0 natsort==5.5.0 nbclient==0.5.3 nbconvert==5.6.1 nbformat==5.1.2 nest-asyncio==1.5.1 networkx==2.5 nibabel==3.0.2 nltk==3.2.5 notebook==5.3.1 np-utils==0.5.12.1 numba==0.44.0 numexpr==2.7.3 numpy==1.16.2 nvidia-ml-py3==7.352.0 oauth2client==4.1.3 oauthlib==3.1.0 okgrade==0.4.3 opencv-contrib-python==4.1.2.30 opencv-python==4.1.2.30 openpyxl==2.5.9 opt-einsum==3.3.0 osqp==0.6.2.post0 packaging==20.9 palettable==3.3.0 pandas==1.1.5 pandas-datareader==0.9.0 pandas-gbq==0.13.3 pandas-profiling==1.4.1 pandocfilters==1.4.3 panel==0.11.1 param==1.10.1 parso==0.8.2 pathlib==1.0.1 patsy==0.5.1 pexpect==4.8.0 pickleshare==0.7.5 Pillow==7.1.2 pip-tools==4.5.1 plac==1.1.3 plotly==4.4.1 plotnine==0.6.0 pluggy==0.7.1 pooch==1.3.0 portpicker==1.3.1 prefetch-generator==1.0.1 preshed==3.0.5 prettytable==2.1.0 progressbar2==3.38.0 prometheus-client==0.10.0 promise==2.3 prompt-toolkit==1.0.18 protobuf==3.12.4 psutil==5.4.8 psycopg2==2.7.6.1 ptyprocess==0.7.0 py==1.10.0 pyarrow==3.0.0 pyasn1==0.4.8 pyasn1-modules==0.2.8 pycocotools==2.0.2 pycparser==2.20 pyct==0.4.8 pydata-google-auth==1.1.0 pydot==1.3.0 pydot-ng==2.0.0 pydotplus==2.0.2 PyDrive==1.3.1 pyemd==0.5.1 pyerfa==1.7.2 pyglet==1.5.0 Pygments==2.6.1 pygobject==3.26.1 pymc3==3.7 PyMeeus==0.5.11 pymongo==3.11.3 pymystem3==0.2.0 PyOpenGL==3.1.5 pyparsing==2.4.7 pyrsistent==0.17.3 pysndfile==1.3.8 PySocks==1.7.1 pysptk==0.1.18 pystan==2.19.1.1 pytest==3.6.4 python-apt==0.0.0 python-chess==0.23.11 python-dateutil==2.8.1 python-editor==1.0.4 python-louvain==0.15 python-slugify==4.0.1 python-utils==2.5.6 pytz==2018.9 pyviz-comms==2.0.1 PyWavelets==1.1.1 pyworld==0.2.12 PyYAML==3.13 pyzmq==22.0.3 qdldl==0.1.5.post0 qtconsole==5.0.3 QtPy==1.9.0 regex==2019.12.20 requests==2.23.0 requests-oauthlib==1.3.0 resampy==0.2.2 retrying==1.3.3 rpy2==3.4.3 rsa==4.7.2 scikit-image==0.16.2 scikit-learn==0.22.2.post1 scipy==1.4.1 screen-resolution-extra==0.0.0 scs==2.1.2 seaborn==0.11.1 Send2Trash==1.5.0 setuptools-git==1.2 Shapely==1.7.1 simplegeneric==0.8.1 six==1.15.0 sklearn==0.0 sklearn-pandas==1.8.0 smart-open==4.2.0 snowballstemmer==2.1.0 sortedcontainers==2.3.0 SoundFile==0.10.3.post1 spacy==2.2.4 Sphinx==1.8.5 sphinxcontrib-serializinghtml==1.1.4 sphinxcontrib-websupport==1.2.4 SQLAlchemy==1.4.3 sqlparse==0.4.1 srsly==1.0.5 statsmodels==0.10.2 sympy==1.7.1 tables==3.4.4 tabulate==0.8.9 tblib==1.7.0 tensorboard==2.4.1 tensorboard-chainer==0.4.0 tensorboard-plugin-wit==1.8.0 tensorflow==2.4.1 tensorflow-datasets==4.0.1 tensorflow-estimator==2.4.0 tensorflow-gcs-config==2.4.0 tensorflow-hub==0.11.0 tensorflow-metadata==0.29.0 tensorflow-probability==0.12.1 termcolor==1.1.0 terminado==0.9.3 testpath==0.4.4 text-unidecode==1.3 textblob==0.15.3 textgenrnn==1.4.1 Theano==1.0.5 thinc==7.4.0 tifffile==2021.3.31 toml==0.10.2 toolz==0.11.1 torch==1.8.1+cu101 torchsummary==1.5.1 torchtext==0.9.1 torchvision==0.9.1+cu101 tornado==5.1.1 tqdm==4.41.1 traitlets==5.0.5 tweepy==3.10.0 typeguard==2.7.1 typing-extensions==3.7.4.3 tzlocal==2.1 uritemplate==3.0.1 urllib3==1.24.3 vega-datasets==0.9.0 wasabi==0.8.2 wcwidth==0.2.5 webencodings==0.5.1 Werkzeug==1.0.1 widgetsnbextension==3.5.1 wordcloud==1.5.0 world4py==0.1.1 wrapt==1.12.1 xarray==0.15.1 xgboost==0.90 xkit==0.0.0 xlrd==1.1.0 xlwt==1.3.0 yellowbrick==0.9.1 zict==2.0.0 zipp==3.4.1 conda install python==3.7.10 cupy-cuda101を100 become-yukarin==1.0.0 yukarin を削除 Collecting editdistance==0.5.3 Downloading editdistance-0.5.3-cp37-cp37m-win_amd64.whl (23 kB) ERROR: Could not find a version that satisfies the requirement en-core-web-sm==2.2.5 ERROR: No matching distribution found for en-core-web-sm==2.2.5 とりあえず削除 ERROR: Could not find a version that satisfies the requirement ideep4py==2.0.0.post3 ERROR: No matching distribution found for ideep4py==2.0.0.post3 削除 ERROR: Could not find a version that satisfies the requirement jaxlib==0.1.64+cuda110 ERROR: No matching distribution found for jaxlib==0.1.64+cuda110 cuda100にしてみた だめ ERROR: Could not find a version that satisfies the requirement jaxlib==0.1.64+cuda100 ERROR: No matching distribution found for jaxlib==0.1.64+cuda100 pip install jaxlib==0.1.64 だめ 消去 ERROR: Could not find a version that satisfies the requirement pygobject==3.26.1 ERROR: No matching distribution found for pygobject==3.26.1 削除 Collecting rpy2==3.4.3 Downloading rpy2-3.4.3.tar.gz (188 kB) |████████████████████████████████| 188 kB 6.8 MB/s ERROR: Command errored out with exit status 1: command: 'G:\anaconda3\envs\googleyuka\python.exe' -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'C:\\Users\\yuki\\AppData\\Local\\Temp\\pip-install-p9vmu_6r\\rpy2_0a417b7ec76b44ab977d91c13a2df161\\setup.py'"'"'; __file__='"'"'C:\\Users\\yuki\\AppData\\Local\\Temp\\pip-install-p9vmu_6r\\rpy2_0a417b7ec76b44ab977d91c13a2df161\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base 'C:\Users\yuki\AppData\Local\Temp\pip-pip-egg-info-nc3qyncm' cwd: C:\Users\yuki\AppData\Local\Temp\pip-install-p9vmu_6r\rpy2_0a417b7ec76b44ab977d91c13a2df161\ Complete output (2 lines): Error: rpy2 in API mode cannot be built without R in the PATH or R_HOME defined. Correct this or force ABI mode-only by defining the environment variable RPY2_CFFI_MODE=ABI ['cffi>=1.10.0', 'jinja2', 'pytz', 'tzlocal'] ---------------------------------------- WARNING: Discarding https://files.pythonhosted.org/packages/38/d4/8e79a52dda0f41fced4381f2964c592573ac37df14480be75fbdd55e5587/rpy2-3.4.3.tar.gz#sha256=a39f2d75c24c688d5f48dfb2ef82efc006f2a51591941743026e1182353bf558 (from https://pypi.org/simple/rpy2/). Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output. ERROR: Could not find a version that satisfies the requirement rpy2==3.4.3 ERROR: No matching distribution found for rpy2==3.4.3 削除 ERROR: Could not find a version that satisfies the requirement screen-resolution-extra==0.0.0 ERROR: No matching distribution found for screen-resolution-extra==0.0.0 削除 ERROR: Could not find a version that satisfies the requirement torch==1.8.1+cu101 ERROR: No matching distribution found for torch==1.8.1+cu101 削除 ERROR: Could not find a version that satisfies the requirement torchvision==0.9.1+cu101 ERROR: No matching distribution found for torchvision==0.9.1+cu101 削除 ERROR: Could not find a version that satisfies the requirement xkit==0.0.0 ERROR: No matching distribution found for xkit==0.0.0 削除 googlecolabから最初から入っているいらない奴と、 さらに pip install folium==0.2.1 pip install numpy==1.16.2 pip install imgaug==0.2.5 pip install librosa pip install pysptk pip install pyworld pip install fastdtw pip install matplotlib pip install chainerui==0.3.0 pip install tqdm pip install world4py pip install tensorboard-chainer==0.4.0 pip install git+https://github.com/Hiroshiba/become-yukarin pip install git+https://github.com/Hiroshiba/yukarin pip install llvmlite==0.32.1 pip install numba==0.44 pip install cupy-cuda100==5.4.0 最終的には alembic==1.5.8 appdirs==1.4.4 APScheduler==3.7.0 audioread==2.1.9 become-yukarin @ git+https://github.com/Hiroshiba/become-yukarin@99a4998f4b7b9def2079c42be0edfc70201a1856 certifi==2020.12.5 cffi==1.14.5 chainer==5.4.0 chainerui==0.3.0 chardet==4.0.0 click==7.1.2 cupy-cuda100==5.4.0 cycler==0.10.0 Cython==0.29.22 decorator==4.4.2 fastdtw==0.3.4 filelock==3.0.12 Flask==1.1.2 folium==0.2.1 greenlet==1.0.0 HeapDict==1.0.1 idna==2.10 imageio==2.9.0 imageio-ffmpeg==0.4.3 imgaug==0.2.5 importlib-metadata==3.10.0 itsdangerous==1.1.0 Jinja2==2.11.3 joblib==1.0.1 kiwisolver==1.3.1 librosa==0.6.3 llvmlite==0.32.1 Mako==1.1.4 MarkupSafe==1.1.1 matplotlib==3.4.1 moviepy==1.0.3 msgpack==1.0.2 networkx==2.5.1 numba==0.44.0 numpy==1.20.2 packaging==20.9 pandas==1.2.3 Pillow==8.2.0 pooch==1.3.0 proglog==0.1.9 protobuf==3.15.8 pycparser==2.20 pyparsing==2.4.7 pysptk==0.1.18 python-dateutil==2.8.1 python-editor==1.0.4 pytz==2021.1 PyWavelets==1.1.1 pyworld==0.2.12 requests==2.25.1 resampy==0.2.2 scikit-image==0.18.1 scikit-learn==0.24.1 scipy==1.6.2 six==1.15.0 SoundFile==0.10.3.post1 SQLAlchemy==1.4.7 tensorboard-chainer==0.4.0 threadpoolctl==2.1.0 tifffile==2021.4.8 tqdm==4.60.0 typing-extensions==3.7.4.3 tzlocal==2.1 urllib3==1.26.4 Werkzeug==1.0.1 wincertstore==0.2 world4py==0.1.1 xarray==0.15.1 xgboost==0.90 xlrd==1.1.0 xlwt==1.3.0 yellowbrick==0.9.1 yukarin @ git+https://github.com/Hiroshiba/yukarin@85f39e21cc8f393396f8c575dec4e297d352dd5a zict==2.0.0 zipp==3.4.1 結論 linuxやgooglecolab特有のものなどを消したりしたが結局動かないものは動かない yukarinで改めて一段階の学習 どうもbecome-yukarinとyukarinの関係がわからなかったのだが、自分の中で整理すると、 become-yukarin内で1,2段階学習したのち1,2段階音声変換をするのは昔の手法 yukarinで1段階学習かつ変換し、become-yukarinで2段階学習したものを使ってyukarindで2段階変換するのが新しい手法 なおrealtimeで変換するのは後者の方法みたいだ。 windowでyukarinで特徴量抽出 最初のほうにやった通りにwindowsで実行 googlecolabでyukarinのtrain.py 最初に書いた通り、windowsではnumpyの板挟みにあって動かないので、googlecolabで実行 colab上でyukarin1,2段階変換 とりあえずgooglecolab上で実行できた。 しかし2段階の学習が全然だったため、全然いい感じに変換できなかった。 ぼやき numpyがなぜうまくいかないんだ trainに学習のセーブアンドロード機能をなぜつけなかったんだ(特に2段階) 2段階の特徴量抽出でなぜimapで動かすとPathが使えなくなるんだ 全体的にわからないことが多い。特に学習モデルとか きりたんのデータセットはいかが使えそう まとめ 特にまとめることもせず、時系列順に起きたことを書いていたら結構な量になってしまいました。特にnumpyの問題やPathの問題は原因がわからずあきらめてしまいました。 最終的に 第一段階yukarin 特徴量抽出windows 学習googlecolab 学習後テストgooglecolab 第二段階become-yukarin 特徴量抽出windowsでforに変形してゆっくりor googlecolab 学習windows 学習後テストgooglecolab となりました。 いったんこの記事は公開しますが、後々きれいにするかもしれないです。 参考にしたサイト
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python】pandasというライブラリを使ってCSVファイルを読み込み、円グラフを作成する。

pythonを使用してExcelファイルの操作を勉強しています。 本日の気づき(復習)は、CSVの読み込みとグラフ作成に関しての続きです。 pythonでExcelを操作するため、openpyxlというパッケージを使用しています。 売上.csv 部門,1月,2月,3月 商品A,600,700,800 商品B,4100,3800,4500 商品C,2900,1800,3000 商品D,800,900,1000 商品E,600,550,720 前回同様、上記のようなCSVファイルを読み込み この様な円グラフを作り貼り付けたいです。 PieChartオブジェクト 円グラフ作成にはPieChartオブジェクトを使用します。 グラフの作成方法自体は棒グラフと同じですが 気を付けるポイントが2点あります。 円グラフに表示する順番 各データの割合表示 どちらも円グラフを作成する場合は大事なポイントだと思います。 円グラフに表示する順番 DataFrame.sort_values(by='ソートする項目', ascending=昇順は「True」,降順は「False」) 円グラフでデータを確認する場合は 占める割合の大きいものから順に表示したいので CSVデータを張り付ける前にデータをソートしてしまいたいです。 そこで、上記のDataFrame.sort_valuesメソッドを使ってソートします。 各データの割合表示 pie.dataLabels = DataLabelList() pie.dataLabels.showPercent = True 円グラフはデフォルトでは割合表示がされていないみたいです。 表示するためには、PieChartオブジェクトの DataLabelList.showPercent属性をTrueにします。 最終的なコード import pandas as pd from openpyxl import Workbook from openpyxl.chart import PieChart, Reference from openpyxl.chart.label import DataLabelList from openpyxl.utils.dataframe import dataframe_to_rows wb = Workbook() ws = wb.active # CSVファイル読込み df = pd.read_csv('売上.csv', encoding='utf-8') # データを降順でソート df = df.sort_values(by='1月', ascending=False) for row in dataframe_to_rows(df, index=None, header=True): # データを1行ずつ追加 ws.append(row) # 円グラフを選択 pie = PieChart() # 円グラフのスタイル設定 pie.style = 2 # グラフのデータ範囲を設定 data = Reference(ws, min_col=2, min_row=2, max_row=ws.max_row) # ラベルの範囲を設定 labels = Reference(ws, min_col=1, min_row=2, max_row=ws.max_row) # グラフにデータを追加 pie.add_data(data) # 円グラフのラベルを追加 pie.set_categories(labels) #割合をパーセント表示 pie.dataLabels = DataLabelList() pie.dataLabels.showPercent = True pie.title = '部門別売上' # 棒グラフをシートに追加 ws.add_chart(pie, 'A9') wb.save('部門別売上_円グラフ.xlsx') 何とかできました。ソートとかは使い勝手のいいメソッドなので 早めに知る事が出来て良かったです。 おまけ pie.styleの種類 pie.styleには、 1~48までの整数値を指定することでスタイルを変更できるのですが 一覧表みたいなものが見つけられませんでした。 ということで、上記の応用でこんなものを作りました。 import pandas as pd from openpyxl import Workbook from openpyxl.chart import PieChart, Reference from openpyxl.chart.label import DataLabelList from openpyxl.utils.dataframe import dataframe_to_rows wb = Workbook() ws = wb.active # CSVファイル読込み df = pd.read_csv('売上.csv', encoding='utf-8') # データを降順でソート df = df.sort_values(by='1月', ascending=False) for row in dataframe_to_rows(df, index=None, header=True): # データを1行ずつ追加 ws.append(row) for i in range(1, 49): pie = PieChart() pie.style = i data = Reference(ws, min_col=2, min_row=2, max_row=ws.max_row) labels = Reference(ws, min_col=1, min_row=2, max_row=ws.max_row) pie.add_data(data) pie.set_categories(labels) pie.dataLabels = DataLabelList() pie.dataLabels.showPercent = True pie.title = f'{i}' ws.add_chart(pie, f'A{(i-1)*16+9}') wb.save('部門別売上_円グラフ一覧.xlsx') 試しに作ってみましたが、意外と面白いです。 個人的にはスタイル「10」がお気に入りです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

python 演算子を使って計算する

初めに 初学者です。アウトプットすることで定着を目的としています。 演算子を使い計算結果を表示する では、まず簡単な式からやっていきます。 ちなみに計算結果を表示するには、print関数を使いカッコの中に式を書いていきます。 print( 1 + 2 * 3 ) 上記の結果は7です。 上記の文を日本語に直して読んでみると数値2に数値3をかけた結果を数値1に足して結果を表示しろになります。 すごく簡単な文ですが何点かポイントがあります。 ポイント 1つ目はpythonの計算式も優先順位があり足し算,引き算より先に掛け算,割り算が優先される点。 2つ目は、カッコの中から式を優先すると言うこと。 もし上記の式で先にprintが優先されていた場合、表示結果は1+2*3になっているはずです。 また、複数の計算をするときもこれは当てはまります。例えば上記の式にカッコを付け加えてみます。 print( (1 + 2) * 3) すると、カッコの中の1+2の優先順位が先になり数値1に数値2を足した結果に数値3を掛けて表示しろになり結果は6になります。 3つ目は数値は文字列ではないので『'』や『"』で囲わないことです。 主な演算子のまとめ では主な演算子をまとめます。 演算子 計算式 + 足し算 - 引き算    * 掛け算 / 割り算    // 割り算(小数点は切り捨て) % 余り算 他にもありますが上記の表が主な演算子です。 ちなみに恥ずかしながら余り算が最初理解できなかったのですが、 要するに割り算で余った数を出すことだそうです。 >>> print(11%5) 1 上記の例だと数値11を数値5でわり余った数値1を表示すると言うことです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VAEによる画像検索システム

Fashion-MNISTを利用して、類似画像の検索システムを作成しました。方法としては、VAEにより次元圧縮をして、潜在空間上で距離が近いものを検索結果としました。 ソースコードは以下から触れます。 データについて Fashion-MNISTは70,000サンプルのファッション商品の写真で、以下のようになっています。 各ラベルは以下のようになっています。(このラベルは直接的には使いませんが、検索した際に同じラベルのものが出力されたら、有効性を見出せるという意味で使用します。) ラベル 記述 0 T-shirt/top 1 Trouser 2 Pullover 3 Dress 4 Coat 5 Sandal 6 Shirt 7 Sneaker 8 Bag 9 Ankle boot ※データセットの配布元: GitHub「fashion-mnist/zalandoresearch」。The MIT License (MIT) Copyright © [2017] Zalando SE, https://tech.zalando.com ※出典: Fashion-MNIST: a Novel Image Dataset for Benchmarking Machine Learning Algorithms. Han Xiao, Kashif Rasul, Roland Vollgraf. arXiv:1708.07747 また、ネットワークは以下のようなものを用います。 エンコーダー デコーダー VAEの結果 作成したVAEモデルは以下のような結果になりました。 訓練結果 最初はテストデータの誤差が異常に大きくなっていましたが、正常に訓練できています。 再現画像 上段が訓練データ、下段がテストデータで、隣合う二つが元画像と再現後の画像となっています。 概ね再現できているとみて問題なさそうです。 検索結果 index=15の画像に対して、似た画像を検索しました。distanceが距離(2乗和)です。 index distance label 0 15 0.000000 3 1 4648 0.801960 3 2 15393 1.194853 3 3 16060 1.561346 3 4 10346 1.677270 3 5 13806 1.683182 3 6 1672 2.047508 3 7 1921 2.118745 3 8 13082 2.165989 3 9 2797 2.166618 3 10 4243 2.315314 3 11 15704 2.385199 3 12 15119 2.390874 3 13 13158 2.433088 3 14 7793 2.462667 3 15 4905 2.485209 3 16 7603 2.495291 3 17 11167 2.570958 3 18 11551 2.619137 3 19 5991 2.628919 3 画像で見ると以下のようになっています。 左上が検索に利用した画像で、似ている画像が順番に上段の左から右、下段の左から右に表示されています。 なお、検索する画像・検索対象の画像はテストデータのものを用いています。 検索結果としては、概ね同じラベルのものが返ってきていますし、実際の画像も似ている雰囲気のものが抽出されているので、似ているものを抽出する機構としてはうまくいっているように感じます。実は最初はCIFAR-10でやろうとしていたのですが、カラー画像だとVAEの学習がどうしてもうまくいかないようだったので、白黒のデータセットであるFashion-MNISTに変更しました。 実用上は(一応グレスケにすれば可能ではありますが)カラー画像でできることが重要だと考えられるので、今後の課題としたいと思います。 ソースコード 参考文献 VAEとGANを活用したファッションアイテム検索システム PyTorch+Google ColabでVariational Auto Encoderをやってみた
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Python、Lambda、API GatewayでLINEチャットBotを作る

今回はline-bot-sdk-pythonを使わずにAWSのLambdaとAPI Gatewayでオウム返しLINEチャットボットを作ったので投稿します。AWS初心者が初めてのLambdaとAPI Gatewayに挑みました。 LINE Developersへのチャネル登録 https://developers.line.biz/ja/services/messaging-api/ を開いて「今すぐはじめよう」を押してチャンネルを作成してください。 AWS Lambdaの関数の作成 Lambdaの画面に遷移して関数を一から作成しましょう。 関数名はLINEBot、ランタイムはPython 3.8 にします。そして関数の作成を押しましょう。 あとLambdaの環境設定を編集しましょう 値のところにMessaging APIのChannel access token(めちゃくちゃ長いやつ)をコピペして保存してください。 ここから「lambda_function.py」を編集して実際にコードを書いていきます。 lambda_function.py の編集 lambda_function.py import logging import os import urllib.request import json logger = logging.getLogger() logger.setLevel(logging.INFO) def lambda_handler(event, context): logger.info(event) # bodyの中身がJSONの文字列でeventsをループで回す for message_event in json.loads(event['body'])['events']: logger.info(json.dumps(message_event)) url = 'https://api.line.me/v2/bot/message/reply' # リクエストヘッダー headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + os.environ['ACCESSTOKEN'] } # リクエストボディ data = { 'replyToken': message_event['replyToken'], 'messages': [ { "type": "text", "text": message_event['message']['text'], } ] } req = urllib.request.Request(url=url, data=json.dumps(data).encode('utf-8'), method='POST', headers=headers) with urllib.request.urlopen(req) as res: logger.info(res.read().decode("utf-8")) return { 'statusCode': 200, 'body': json.dumps('Hello from Lambda!') } loggerはCloud Watchでlogを出力しているのでなくてもいいです! https://developers.line.biz/ja/reference/messaging-api/#send-reply-message 公式に下記のような方法でPOSTリクエストすれば良いと書いてありました。 HTTPリクエスト POST https://api.line.me/v2/bot/message/reply リクエストヘッダー Content-Type application/json Authorization Bearer {channel access token} リクエストボディ replyToken Webhookで受信する応答トークン messages 送信するメッセージ そしてオウム返しするには下記のような構造になっていたので "events":[{ "replyToken":"xxxxxxxxxxxxxxxxxxx", "message":{"type":"text","id":"xxxxxxxxxxxxxxx","text":"こんにちは"} }] "text": message_event['message']['text']でオウム返しできる。 API Gatewayの設定 Lambdaの先ほど作成したLINEBotの「関数の概要」より、「トリガーを追加」ボタンを押します。「トリガーを選択」では「API GateWay」、「APIを作成する」をそれぞれ選択し、APIタイプは「HTTP」を選択します。セキュリティは今回は「オープン」を選択します。ここまでできたら「追加」ボタンを押します。 そして作成したトリガーのAPIエンドポイントをコピーしてMessaging APIのWebhookのURLに貼り付けます。  完成 そうするとこのようにオウム返しチャットbotの完成です !!  参考文献 ・ https://qiita.com/taku-0728/items/c80bcf65aba318ac6db0 ・ https://blog.5000164.jp/2017/8/14/line-bot/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PythonでOSコマンドの実行

フォアグラウンド subprocess.run(["ls", "-l"]) バックグラウンド subprocess.Popen(["/usr/bin/git", "commit", "-m", "Fixes a bug."]) 参考URL
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

機械学習初心者がface_recognitionライブラリを使ってつまずいたところ

顔画像認識アプリを作成するにあたって、つまずいたところをメモとして書き留めます。 スクレイピングで集めてきた画像から顔だけ切り取りをしたいけど、OpenCVだと正常に切り取れない!(耳だけ切り取られた画像が出力されたなど)ということがあったので、face_recognitionライブラリを使って顔だけ切り取りを行いました。 その際にエラーが発生し原因が分からず、悩んでしまったのでメモします。 (著作権に引っ掛かってしまいそうなので、画像の添付は省略させていただきます) 使用環境 * google colaboratory * face-recognition-1.3.0 顔の特徴量が見つけられない場合、発生するエラー 例えば横向きの画像を以下のコードで切り取りを行おうとすると #face_recognitionはpip install する必要あり #!pip install face_recognition import face_recognition import cv2 #jimin.jpgは横向きの画像 img_cv2 = cv2.imread('jimin.jpg') image = face_recognition.load_image_file('jimin.jpg') face_locations = face_recognition.face_locations(image, model='cnn', number_of_times_to_upsample=2) print(face_locations) #顔の切り出しを行うために各変数に値を保持する top = face_locations[0][0] right = face_locations[0][1] bottom = face_locations[0][2] left = face_locations[0][3] print('top:',top, 'right:',right, 'bottom:',bottom, 'left:',left) #顔のトリミング img_face = img_cv2[top:bottom, left:right] #トリミングした画像を保存 cv2.imwrite('jimin_change.jpg',img_face) 以下のエラーが発生しました(横向きの画像なので顔の切り取りができないのは承知です)。 (実際に使用したデータは顔の輪郭がぼけていたりしていました) [] --------------------------------------------------------------------------- IndexError Traceback (most recent call last) <ipython-input-9-a65f96f2cfc8> in <module>() 10 11 #顔の切り出しを行うために各変数に値を保持する ---> 12 top = face_locations[0][0] 13 right = face_locations[0][1] 14 bottom = face_locations[0][2] IndexError: list index out of range 変数face_locations が [] と出力されました。 face recognitionライブラリの公式のサイトhttps://face-recognition.readthedocs.io/en/latest/face_recognition.html#face_recognition.api.face_locations を見てみると、返り値はA list of tuples of found face locations in css (top, right, bottom, left) order と記載がありました。 確かに配列が出力されています。 私がやりたかったのは、指定したディレクトリ内の複数の画像から顔の切り出しを行うことだったので、顔が認識されずにエラーになってしまうのは不都合でした。 (for文でディレクトリ内のファイルを読み込んで顔の切り取りを行いたかったので、途中でエラーが発生するとなかなか作業が進まない、、、) 顔の特徴量が見つけられない場合は、その画像をそのまま出力させてしまおう とにかくエラーを回避するために以下のようにコードを修正しました。 #face_recognitionはpip install する必要あり #!pip install face_recognition import face_recognition import cv2 #画像読み込み img_cv2 = cv2.imread('jimin.jpg') #画像のサイズ取得 width = img_cv2.shape[0] height = img_cv2.shape[1] image = face_recognition.load_image_file('jimin.jpg') face_locations = face_recognition.face_locations(image, model='cnn', number_of_times_to_upsample=2) print(face_locations) #face_recognition.face_locations()で顔が認識されない場合、[]が返るので最初に読み込んだ画像をそのまま返す if face_locations == []: face_locations = [(0,width,height,0)] #顔の切り出しを行うために各変数に値を保持する top = face_locations[0][0] right = face_locations[0][1] bottom = face_locations[0][2] left = face_locations[0][3] print('top:',top, 'right:',right, 'bottom:',bottom, 'left:',left)#出力>>>top: 156 right: 722 bottom: 461 left: 418 #顔のトリミング img_face = img_cv2[top:bottom, left:right] cv2.imwrite('jimin_not_change.jpg',img_face) 以下、出力内容です。jimin_not_change.jpgというファイルが生成されました。 [] top: 0 right: 600 bottom: 488 left: 0 True 顔の特徴量が見つからない場合は元の画像を出力させて、指定したディレクトリ内の画像すべてを上記のコードで処理したあと、顔の切り取りができなかった画像は手動で削除する方針で解決しました。 うまく切り出せない画像はそんなに多くなかったので手動でいけました。 他に良い方法があれば教えていただけると幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【画像切り抜き】キレイなお姉たまを自宅へ呼ぼう

■ 0.はじめに 「人物等のオブジェクト切り抜き」をする場合、かつてはチマチマ画像を拡大し選択範囲を指定するなど、作業がとても大変でかつ職人芸でした。ところが、昨今、AI技術を使うことでこの作業をしなくても「ボタン1発」で切り抜きができるようになってきました。 これらはあとで紹介する「webツールサイト」などでも実施可能ですが、費用がかかるサイトが多いのが現状です…お金が無い貧乏人としては、自分でなんとかするしかありません。その昔、おもちゃが買ってもらえず、しかたなく、家にあった割り箸と輪ゴムで、ゴム鉄砲を作って遊んだことを思い出してしまいました?。 そんな訳で、フリープログラムを使っての「人物切り抜き」、いってみましょう! ■ 1.やること キレイなお姉たまを「自宅のお部屋」へ呼びたいと思います?。 汚部屋を掃除し、お部屋へ………準備万端です?むふふふ。 ■ 2.切り抜きの仕組み Githubでそれらしいツールを検索して、起動すれば「オブジェクト切り抜き」は簡単にできてしまうんですが、それではせっかくプログラムで実行している意味がないので、簡単に仕組みも調べておきます。 Alpha Mattingとは 今回実施するオブジェクト切り抜きは「Alpha Matting」という手法を使います。 画像から前景のAlpha値を抽出し、背景と分離することをAlpha Mattingと呼びます。Alpha値とは、各画素での不透明度を表すパラメータです。Alpha Mattingでは、「ソース写真」と「Trimap」と呼ばれる中間データを用いて処理を行います。 Trimapとは Trimapとは、前景であろう領域に白色、背景であろう領域に黒色、どちらか判断できない、または細かくて白と黒では塗り分けられない領域を灰色で塗り分けたものです。「T・R・I」とTrimapを作ってみました。いかがでしょうか?? ツール整理 今回使用するツールについても整理しておきます。本記事ではrembgを使用します。rembgからu2net、pymattingのツールを使用しているようですので、そちらも参考になります。 No. ツール名 説明 ライセンス 1 u2net Trimapを生成するツール Apache License 2.0 2 pymatting Alpha Mattingを処理するツール MIT License 3 rembg 「u2net」と「pymatting」を実行し、オブジェクト切り抜きをするツール MIT License ■ 3.Google Colabで実行 今回は、我らの学び屋「Google Colab」で実行したいと思います。実行環境は、もちろんGoogle Colabでなくても結構です。Google Colabで実行する場合、プログラムを改造した箇所やGoogle Colabへアップロードした画像は、時間が経つと揮発してしまうので注意が必要です。 (1)画像切り抜きプログラムの準備 ●インストール pipでインストール可能です。 2021/04/14現在:rembg 1.0.26 https://pypi.org/project/rembg/ pip公開版はバグ?があるので、もしかしたら最新版をgitからcloneした方が良いかもしれません。 https://github.com/danielgatis/rembg colab !pip install rembg インストール後、次のようにランタイムの再起動を促されたら再起動をしてください。 colab実行結果 WARNING: The following packages were previously imported in this runtime: [PIL,numpy] You must restart the runtime in order to use newly installed versions. [Restart Runtime]ボタンを押下するか、[ランタイム] - [ランタイムを再起動]を押下 ●切り抜き画像アップロード 切り抜き画像として、「sample.png」をアップロードします。 手元にある画像ファイルを「/content」配下にドラッグアンドドロップして、GoogleColabへアップロードしてください。 きちんとアップロードされたか確認します。 colab from IPython.display import Image, display_png display_png(Image('sample.png')) ●rembg実行 それではrembgを起動して切り抜きを行います! colab from rembg.bg import remove import numpy as np import io from PIL import Image input_path = 'sample.png' output_path = 'cutout.png' f = np.fromfile(input_path) result = remove(f, alpha_matting=True, alpha_matting_foreground_threshold=240, alpha_matting_background_threshold=10, alpha_matting_erode_structure_size=6) img = Image.open(io.BytesIO(result)).convert("RGBA") img.save(output_path) ●rembg実行結果 あれ?エラーだ?……… colab --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-2-64027dc30014> in <module>() ----> 1 from rembg.bg import remove 2 import numpy as np 3 import io 4 from PIL import Image 5 1 frames /usr/lib/python3.7/functools.py in lru_cache(maxsize, typed) 488 maxsize = 0 489 elif maxsize is not None: --> 490 raise TypeError('Expected maxsize to be an integer or None') 491 492 def decorating_function(user_function): TypeError: Expected maxsize to be an integer or None ●プログラム変更1 上記エラーの場合、以下のプログラムを修正すれば動くようになります。 /usr/local/lib/python3.7/dist-packages/rembg/bg.py bg.py, line 67 bg.py抜粋 ( 67行目を変更 ) @functools.lru_cache ↓↓↓↓ @functools.lru_cache(maxsize=None) ●プログラム変更2 rembgでは、Trimap画像は保存されないので、ついでに「trimap.png」として画像を保存するように修正してしまいましょう!ちなみにTrimap画像はu2netの学習サイズである320x320で検出されるので、元の画像サイズへリサイズしています。 ※「プログラム変更2」は必須ではありません。割愛してもOKです。 /usr/local/lib/python3.7/dist-packages/rembg/bg.py bg.py, Line85 mask = detect.predict(model, np.array(img)).convert("L") 上記処理のすぐ下に、以下の処理(3行)を追加 追加処理 output_path = '/content/trimap.png' mask = mask.resize(img.size) mask.save(output_path) bg.py抜粋 ( trimapを保存するためにbg.pyに上記処理(3行)を追加 ) def remove( data, model_name="u2net", alpha_matting=False, alpha_matting_foreground_threshold=240, alpha_matting_background_threshold=10, alpha_matting_erode_structure_size=10, ): model = get_model(model_name) img = Image.open(io.BytesIO(data)).convert("RGB") mask = detect.predict(model, np.array(img)).convert("L") output_path = '/content/trimap.png' # ← ここの処理を追加 mask = mask.resize(img.size) # ← ここの処理を追加 mask.save(output_path) # ← ここの処理を追加 ●ランタイムの再起動 プログラムを変更したら、忘れずにランタイムの再起動を実施してください。 [ランタイム] - [ランタイムを再起動]を押下 (2)画像切り抜きプログラムの実行 ●rembg実行コード プログラムを修正したので、再度、以下プログラムを実行して、切り抜きを行っていきます! ※remove関数に渡す引数「alpha matting_xxxx_xxxx」は、適当に変えて遊んでみてください。 colab from rembg.bg import remove import numpy as np import io from PIL import Image input_path = 'sample.png' output_path = 'cutout.png' f = np.fromfile(input_path) result = remove(f, alpha_matting=True, alpha_matting_foreground_threshold=240, alpha_matting_background_threshold=10, alpha_matting_erode_structure_size=6) img = Image.open(io.BytesIO(result)).convert("RGBA") img.save(output_path) Trimap画像「trimap.png」と、AlphaMattingした画像「cutout.png」を表示して確認します。 colab from IPython.display import Image, display_png display_png(Image('trimap.png')) display_png(Image('cutout.png')) なんとか「切り抜き」はうまくいきました!あとはお姉たまを「僕んち」に呼ぶだけです?! (3)写真合成 画像合成については、フリーの画像編集ツールなどでレイヤー貼り付けを行っても同様のことができますが、せっかくなのでこちらもプログラムで実行します。 ●合成する背景をアップロード 合成する背景として、「background.png」と「greenback.png」の2つをアップロードします。 手元にある画像ファイルを「/content」配下にドラッグアンドドロップして、GoogleColabへアップロードしてください。 きちんとアップロードされたか確認します。 colab from IPython.display import Image, display_png display_png(Image('background.png')) display_png(Image('greenback.png')) 僕んちとグリーンバック画像です。 ●「僕んち」背景と合成 colab from PIL import Image # 切り抜き画像 img = Image.open('cutout.png').convert('RGBA') # 背景画像 bg = Image.open('background.png').convert('RGBA') # 画像合成 img_clear = Image.new("RGBA", bg.size, (255, 255, 255, 0)) img_clear.paste(img, (200,250)) bg = Image.alpha_composite(bg, img_clear) # 画像保存 bg.save('merge1.png') 作成された合成画像を表示します。 colab from IPython.display import Image, display_png display_png(Image('merge1.png')) 僕んちにキター?!ワッショイ・ワッショイ♫ ●「グリーンバック」背景と合成 colab from PIL import Image # 切り抜き画像 img = Image.open('cutout.png').convert('RGBA') # 背景画像 bg = Image.open('greenback.png').convert('RGBA') # 画像合成 img_clear = Image.new("RGBA", bg.size, (255, 255, 255, 0)) img_clear.paste(img, (200,250)) bg = Image.alpha_composite(bg, img_clear) # 画像保存 bg.save('merge2.png') 切り抜き画像とグリーンバック画像を合成した画像を表示します。 colab from IPython.display import Image, display_png display_png(Image('merge2.png')) ゴチャゴチャしない背景(グリーンバック)で、うまく切り取れているか確認してみます。 少しエッジが甘いところがありますが、まぁまぁできていますね! ■ 4.オブジェクト切り抜きサイト紹介 プログラムを実行しなくても、webツールを実行することで切り抜きを行うこともできます。対価支払いについては、AIの開発などを続けて認識精度を向上させるためなのか、気軽さなのか分かりませんが、サブスクが多いですね。他にも有効なwebサイトがあったら教えてください。ちな、順不同です。 サイト 切り抜き結果 個人的な感想 点数 Clipping Magic 自動切り抜きもキレイだし、切り抜き後の調整ツールが秀悦でとても使いやすいです。ヘアツール、フォアグラウンド指定やバックグラウンドの範囲指定が自動でできたり、きめ細かな修正が簡単に実施可能です。有料でサンプルには透かしが入っています。 100 remove.bg 自動切り抜き後は、簡単な手動によるフォアグラウンドの範囲削除/復元ツールの様なものはありましたが、それだけでは切り抜きのきめ細かな調整はできません。有料ですが、小さなプリビュー画像は無料でダウンロード可能です。 80 removal.ai 手と首元の間を見るとremove.bgよりも良いかもしれません。自動切り抜き後のペイントツールが充実していますが、それより切り抜き調整ツールが欲しかった。有料ですが、小さなプリビュー画像は無料でダウンロード可能です。 81 Photo Scissors 自動切り抜き後にヘアーツール、フォアグラウンド指定ツールなどがあります。フォアグラウンドツールで同じ様な範囲が自動で選択されないところや、バックグラウンドが指定できないところなどから、Clipping Magicには及びません。有料ですが、小さなプリビュー画像は無料でダウンロード可能です。 85 ■ 5.以上 お疲れ様でした。 実際に「画像切り抜き」をやってみて、髪の毛など切り抜きが難しいところでも、自動で難なく切り取りができてしまうのは、本当にAIさまの「おチカラ」はスゴイですね!今までできなかったことが、続々と自動でできるようになっています。ただ、処理はまだまだ完全ではないので、Clipping Magicの様に、いかに簡単に補正をできるようにするかなどの機能も合わせて必要だと思いました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Djangoで既存のPostgreSQLを利用

はじめに Djangoチュートリアル③(モデルの作成、Django Admin)ではデフォルトの SQLite データベースの設定を行った。本記事では、PostgreSQL の設定を試してみる。あらかじめ存在している AWS 上に構築されている PostgreSQL を利用するため、①データベースの設定、②データベースからモデルを定義、③マイグレーションまで行う。Integrating Django with a legacy database を参考にした。 ①データベースの設定 まず config/settings.py におけるデフォルト設定(SQLite)を以下に示す。SQLite の 'NAME' は使用するファイルの絶対パスを指定している。 config/settings.py DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } } 上記を以下のように変更する。 config/settings.py DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': [database_name], 'USER': [user_name], 'PASSWORD': [password], 'HOST': ***.amazonaws.com, 'PORT': '5432' } } SQLite では 'ENGINE' として 'django.db.backends.sqlite3' としていたのを、'django.db.backends.postgresql' に変更しており、あとは DB の設定で必要とされるものを順に指定している。 さらに以下コマンドで PostgreSQL のドライバとして paycopg2-binary をインストールする。 $ pip install psycopg2-binary 上記で行ってきたデータベースの設定で正しく接続できているかは以下コマンドで確認できる。 $ python manage.py dbshell ②データベースからモデルを定義 既存のデータベースを使用しているため、当然モデルの定義がされておらず、Django ORM を使用することができない。Django ではデータベースからモデルを自動生成する inspectdb コマンドが準備されているので、それを利用してモデルを定義する。以下コマンドでは、出力結果をそのまま [app_name]/models.py に保存している。 $ python manage.py inspectdb > [app_name]/models.py 各モデルクラス内のサブクラスである class Meta の項目が意味するものは以下。 - managed:各テーブルの作成、変更、および削除を管理するかどうか。デフォルトでは False。 - db_table:テーブル名。 モデルを定義できたので、有効化するために config/settings.py の INSTALLED_APPS に登録しておく。登録する方法はDjangoチュートリアル③(モデルの作成、Django Admin)のモデルの有効化と同様。 ③マイグレーション 以下コマンドでマイグレーションを行う。 $ python manage.py makemigrations [app_name] $ python manage.py migrate テーブルのアクセスは以下コマンドなどで確認できる。 $ python manage.py shell >>> from [app_name].models import [model_name] >>> [model_name].objects.all() おわりに 既存のデータベースからモデルを自動作成でき、非常に便利なことがわかった。新規データベースでも、モデルを定義するよりデータベースを先に作ってそれからモデルの自動作成をした方が楽なのかも。わかったことがあれば、追記していきたい。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

New Relic SyntheticsモニターのIP範囲をセキュリティグループに反映させるPythonスクリプト

概要 AWS上のサーバーに対してNew Relic SyntheticsによってURL監視をする際に、セキュリティグループで制限をかけている場合に、インバウンドルールにNew Relic SyntheticsモニターのIPを許可ルールに追加したいことがある。その追加・更新のPythonスクリプトを書いた セキュリティグループの更新スクリプト 内容 New Relicで公開されているIPアドレス一覧を取得し、任意のロケーションのIPアドレスを指定のセキュリティグループに対して、その許可ルールを設定する。 https://docs.newrelic.com/docs/synthetics/synthetic-monitoring/administration/synthetic-public-minion-ips/ 新規追加と更新に対応しており、将来、上記のIPアドレスリストに変更があった場合に、その変更も反映できる。 インバウンドルール更新時のルールの識別 セキュリティグループのルールにはIDがなく、ルールを指定して更新することができない。 そこで、各ルールの「Description」を利用し、本スクリプトで更新対象とするルールかどうかの識別を行う。 ルール追加時に New Relic Synthetics Monitor を識別文字列としてルールのDescriptionに設定し、ルールの更新時にはこのDescriptionが設定されているルールが対象となって更新される。 更新の流れ AWS APIの関係で、対象となったルールは変更がなくても一度全て削除されて改めて追加されるという流れになっている。これは、セキュリティグループ内の全てが対象ではなく、Descriptionによって更新対象と識別されたもののみ。 スクリプトの利用 ライブラリインストール (初回のみ) pip install boto3 pip install requests コード update_sg.py import boto3 import copy import requests URL_NR_SYNTHETICS_IP_RANGE = "https://s3.amazonaws.com/nr-synthetics-assets/nat-ip-dnsname/production/ip.json" SG_DESCRIPTION = "New Relic Synthetics Monitor" # Set location labels NR_LOCATIONS = [ "Tokyo, JP", "San Francisco, CA, USA" ] def get_nr_synthetics_ip_range(locations: list): res = requests.get(URL_NR_SYNTHETICS_IP_RANGE) ips_per_location = res.json() ips = [] for location in locations: ips.extend(ips_per_location[location]) ip_ranges = ["{}/32".format(ip) for ip in ips] return ip_ranges def update_sg(security_group_id: str, port: int, protocol: str, cider_ips: list, desc: str, aws_profile: str = None, aws_region: str = "ap-northeast-1", ): """ Update security group """ if aws_profile is not None: session = boto3.session.Session(profile_name=aws_profile, region_name=aws_region) client = session.client("ec2") else: client = boto3.client("ec2") print("Describe current rules.") res = client.describe_security_groups(GroupIds=[security_group_id,]) security_groups = res["SecurityGroups"] if len(security_groups) < 1: return security_group = security_groups[0] print(security_group) del_ip_permissions = [] for ip_perm in security_group["IpPermissions"]: if ip_perm.get("FromPort") == port and ip_perm.get("ToPort") == port and ip_perm.get("IpProtocol") == "tcp": del_ip_ranges = [ip_range for ip_range in ip_perm["IpRanges"] if ip_range.get("Description") == desc] del_ip_perm = copy.deepcopy(ip_perm) if len(del_ip_ranges) > 0: del_ip_perm["IpRanges"] = del_ip_ranges del_ip_permissions.append(del_ip_perm) if len(del_ip_permissions) > 0: print("Delete current rules.") print(del_ip_permissions) client.revoke_security_group_ingress( GroupId=security_group_id, IpPermissions=del_ip_permissions, ) else: print("No deletion targets.") print("add rules") added_ip_ranges = [] for cidr_ip in cider_ips: ip_range = { "CidrIp": cidr_ip, "Description": desc } added_ip_ranges.append(ip_range) print(added_ip_ranges) client.authorize_security_group_ingress( GroupId=security_group_id, IpPermissions=[ { 'FromPort': port, 'IpProtocol': protocol, 'IpRanges': added_ip_ranges, 'ToPort': port, }, ], ) if __name__ == "__main__": import argparse parser = argparse.ArgumentParser(description="Update security groups to allow New Relic Synthetics Monitor access.") parser.add_argument('sg_id', type=str, help="Security Group ID") parser.add_argument('--port', type=int, default=80) parser.add_argument('--protocol', type=str, default="tcp") parser.add_argument('--description', type=str, default=SG_DESCRIPTION) parser.add_argument('--aws-profile', type=str, default=None) parser.add_argument('--aws-region', type=str, default=None) args = parser.parse_args() ips = get_nr_synthetics_ip_range( NR_LOCATIONS ) update_sg(args.sg_id, args.port, args.protocol, ips, args.description, args.aws_profile, args.aws_region, ) 実行例 python update_sg.py {セキュリティグループID} --aws-profile {AWSプロファイル} --aws-region {AWSリージョン} 実行すると、このように設定される。 リポジトリ 補足 ポートおよびプロトコル単位での設定となる (デフォルトはTCP:80)。指定する場合は、実行時に --portや --protocol フラグで指定可能 ルールのDescriptionを変更する場合は--description フラグで指定可能 Syntheticsのロケーションを変更する場合は、コード内の NR_LOCATIONS を編集
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Google Earth Engineから衛星プロダクトをまとめてダウンロード(改)

概要  Google earth engine上には多数のデータが用意されています。特にMODISセンサーに基づいたプロダクトは多く、広く使われています。しかしながら、MODISプロダクトはmodis sinusoidalと呼ばれる投影法に基づいており、そのままでは一般的な緯度経度座標への投影になっていません。pyproj等を用いた投影変換も可能ですが、GEEを用いる事で、緯度経度座標でのダウンロードが可能です。本記事では、複数年に渡るデータをまとめてダウンロードしつつ、投影変換を行い、日付情報を付加してgoogle driveへ保存する方法についてご紹介したいと思います。 データ  今回ダウンロードしたのは、地表面反射率の8日間平均であるMOD09A1プロダクトです。以下の画像はmodis sinusoidalがどの様に設定されているのかを示したものです。見慣れた形式(緯度経度)と比べて、ひしゃげた様な形状になっているのが分かります(画像ソース)。sinusoidal projectionの簡単な歴史や投影法の特徴については、Wikipediaに載っています。 コード  以下のコードについては、以下のリンク からGoogle ColabにてNotebook形式でもアクセスが可能です。 GEEbulkDownload.py !pip install earthengine-api !pip install unidecode !pip install geetools import ee #Googleアカウントの認証を求められます ee.Authenticate() ee.Initialize() from geetools import batch from tqdm import tqdm #パラメータの設定 #ダウンロードしたいプロダクト名 productName="MODIS/006/MOD09A1" #検索期間の開始日 startDate='-01-01' #検索期間の終了日 endDate='-01-30' #画像を保存したいフォルダ名 FolderName='SurfaceReflectance_MOD09A1' #ダウンロードしたいバンドの指定 #赤、緑、青、赤外 band=['sur_refl_b01','sur_refl_b03','sur_refl_b04','sur_refl_b05'] #長方形での対象領域の設定 #詳しい情報: https://developers.google.com/earth-engine/apidocs/ee-geometry-rectangle ROI=ee.Geometry.Rectangle(coords=[140,35.9,140.5,36.2]) #対象年の指定 start_y=2016 #開始年 end_y=2019 #終了年 years=[y for y in range(start_y,end_y+1)] #ダウンロードの実行 for y in tqdm(years): #カウンタの初期化 cnt=0 #対象領域・対象期間におけるデータを検索 start=f'{y}'+startDate end=f'{y}'+endDate ImageCollection_at_y=ee.ImageCollection(productName).filterDate(ee.Date(start), ee.Date(end)).select(band).filterBounds(ROI) #検索結果をリスト形式へ変換 list_of_data=ImageCollection_at_y.toList(ImageCollection_at_y.size().getInfo()) for d in range(list_of_data.size().getInfo()): #画像取得日をファイル名へ指定 name=ee.Image(list_of_data.get(cnt)).date().format('yyyy-MM-dd').getInfo() task=ee.batch.Export.image.toDrive( description= f'{y}_{cnt}', image=ee.Image(list_of_data.get(cnt)), folder=FolderName+f'_{y}', #フォルダ名 region= ROI, fileNamePrefix=name, #ファイル名の指定 fileFormat= 'GeoTIFF', maxPixels= 1e12, #出力される画像のピクセル数上限を設定 scale=500, #出力画像の空間解像度(m) crs='EPSG:4326') #緯度経度座標として、WGS84のEPSGコードを指定 task.start() #処理の開始 cnt+=1 #カウンタの更新 画像の出力例:Google Earthの画像上に重ね合わせてあります。sinusoidal projectionの歪みがなく、表示が一致している事が分かります。バンドの組み合わせは、植生が赤く表示されるフォルスカラー(R/G/B=B5/B1/B4)です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

abc198のメモ

A N = int(input()) ans = 0 if N<2: ans = 0 else: ans = N - 1 print(ans) B N = input() L = len(N) for i in range(L): if int(N[-1]) == 0: N = N[0:L-i-1] for i in range(int(len(N)/2)): if N[i] != N[len(N)-i-1]: print("No") exit() print("Yes") C import math R, X, Y = [int(a) for a in input().split()] dis = math.sqrt(X**2 + Y**2) if dis < R: print(2) elif dis == R: print(1) else: print(math.ceil(dis/R)) D 当日は時間切れで提出できず、残念。 後日じっくり考えたらできた。 itertoolsって初めて使ったけど、競プロで今後も役に立ちそう。 PythonではLTE。同じコードでPypyだと通りました import itertools S = [] strings = [] N = [] for i in range(3): S.append(input()) N.append(list()) for j in range(len(S[i])): strings.append(S[i][j]) N[i].append(0) str_set = set(strings) str_list = list(str_set) if len(str_set) > 10: print("UNSOLVABLE") exit() for v in itertools.permutations(range(10), len(str_set)): if v[str_list.index(S[0][0])] == 0 or v[str_list.index(S[1][0])] == 0 or v[str_list.index(S[2][0])] == 0: continue N123 = [0, 0, 0] for i in range(3): num = "" for j in range(len(S[i])): num += str(v[str_list.index(S[i][j])]) N123[i] = int(num) if (N123[0]+N123[1] == N123[2]) and (N123[0] != 0)and (N123[1] != 0)and (N123[2] != 0): for x in N123: print(x) exit() print("UNSOLVABLE")
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Pythonでサブネットマスクをプレフィックス表記からオクテット表記へ変換する方法

趣旨 socket使う方法もあるけど、あんまり使いたくない人用 コード from ipaddress import IPv4Interface def cidr_to_netmask(cidr:str) -> str: itfc = IPv4Interface('0.0.0.0' + cidr) return str(itfc.netmask) print(cidr_to_netmask('/0')) print(cidr_to_netmask('/8')) print(cidr_to_netmask('/16')) print(cidr_to_netmask('/24')) print(cidr_to_netmask('/32')) 結果 0.0.0.0 255.0.0.0 255.255.0.0 255.255.255.0 255.255.255.255
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python】ゴールデンクロス・デッドクロス売買手法のSMA日数をベイズ最適化してみた

こんにちは,藤野です. 普段はこちらで株式投資に関するブログを書いています. 今回は,『ゴールデンクロス・デッドクロスで売買を判断する手法のバックテスト』に対して,『手法をベイズ最適化』してみます. バックテストについて 以前書いた記事 を基本として行います. この記事では最適化は『Backtesting.py』のoptimize機能を用いましたが,ここを今回はベイズ最適化でやってみようということです. ※注意! 最後で述べるように,Backtesting.pyでもベイズ最適化で探索できるようです(Backtesting.pyのoptimize機能との比較).自作部分は無駄骨になった気がするので,ここだけ読んでいただいても構いません. ベイズ最適化について ベイズ最適化はちょっと雑な手法ですが汎用性は高く,ブラックボックスを最適化するときには手軽で便利です. ただし,汎用性が高いということは精度にはあまり期待できないということなので,多少目をつぶる必要がありますね. なぜベイズ最適化で手法を最適化するのか?と言われたら,何となくです. ほとんどの場合はBacktesting.pyのoptimize機能を使った方が総合的には良い気がしますが,探索範囲が広い場合はベイズ最適化の方が(計算時間の面で)有利になる可能性があるかな~と思っています.ただし,今回のような変数が2つしかなく範囲が狭い場合にはベイズ最適化は微妙でしょう. ベイズ最適化についてのソースコードは,以下の記事を参考にしました. この記事では,Pythonライブラリbayes_optの『Bayesian Optimization』で基本的な関数をベイズ最適化しています. ソースコード 必要なライブラリ 最初に,必要なライブラリを紹介しておきます. #データ取得用 import pandas_datareader.data as web import datetime # バックテスト用 from backtesting import Backtest, Strategy from backtesting.lib import crossover from backtesting.test import SMA # SMAインジケータ #ベイズ最適化用 from bayes_opt import BayesianOptimization #グラフ描画用 from mpl_toolkits.mplot3d import Axes3D from matplotlib import pyplot as plt import numpy as np データ取得用ライブラリpandas_datareader, バックテスト用ライブラリbacktesting, ベイズ最適化用ライブラリbayes_opt はpipでインストールできると思います. もちろん,グラフ描画用のライブラリもpipでインストールできると思います. ソースコードの構成 想像ついているかもしれませんが,こんな感じになっています. ・データ取得部分 ・バックテスト部分(SMAの日数を変数とする関数) ・ベイズ最適化部分(SMAの日数を変数としてバックテストの最終資産額を最大化する) ・出力部分(データやグラフ描画など) つまり,SMAの日数をパラメータとしてベイズ最適化で調整し,バックテストの結果を良くします. 今回は冒頭のバックテストとベイズ最適化の記事をそのまま組み合わせただけなので不格好なコードになっていますが,ご了承ください.わかりずらいところがあれば,冒頭の2つの記事をご覧いただければと思います. データ取得部分 今回は,2018/1/1~現在までのAAPL(Apple)の株でバックテストしたいと思います. import pandas_datareader.data as web import datetime start = datetime.date(2018,1,1) end = datetime.date.today() data = web.DataReader('AAPL', 'yahoo', start, end) バックテスト部分 from backtesting import Backtest, Strategy # バックテスト from backtesting.lib import crossover from backtesting.test import SMA # SMAインジケータ def backtesting(x1, x2): print('x1 :', x1, 'x2 :', x2) class SmaCross(Strategy): n1 = int(x1) # 短期SMA n2 = int(x2) # 長期SMA def init(self): self.sma1 = self.I(SMA, self.data.Close, self.n1) self.sma2 = self.I(SMA, self.data.Close, self.n2) def next(self): #チャートデータの行ごとに呼び出される if crossover(self.sma1, self.sma2): #sma1がsma2を上回った時 self.buy() # 買い elif crossover(self.sma2, self.sma1): self.position.close() #ポジション降りる # バックテストの設定 bt = Backtest( data, # チャートデータ SmaCross, # 売買戦略 cash=1000, # 最初の所持金 commission=0.00495, # 取引手数料 margin=1.0, # レバレッジ倍率の逆数(0.5で2倍レバレッジ) trade_on_close=True # True:現在の終値で取引,False:次の時間の始値で取引 ) output = bt.run() # バックテスト実行 score = output['Equity Final [$]'] print('Equity :', score) return score この関数backtesting(x1, x2)に短期SMAの日数x1と長期SMAの日数x2を入れれば,バックテスト行い,その最終資産額(Equity Final)scoreが返ってきます(このコードの参考はこちら). 最初の所持金は1000です. ただし,SMAを計算するときの日数は離散値(整数)である必要がある一方,ベイズ最適化で決められる変数は連続値なので,int形に変えています(今思ったら,焼きなまし法や遺伝的アルゴリズムとかの方がいいかもですね). ベイズ最適化部分 from bayes_opt import BayesianOptimization x1_max, x1_min = 50, 10 x2_max, x2_min = 50, 10 # 探索するパラメータと範囲を決める pbounds = {'x1': (x1_min, x1_max), 'x2': (x2_min, x2_max), } # 探索対象の関数と、探索するパラメータと範囲を渡す bo = BayesianOptimization(f=backtesting, pbounds=pbounds) # 最大化する bo.maximize(init_points=10, n_iter=90) print('OPTIMIZE: END') このコードの参考はこちら グラフ描画部分 from mpl_toolkits.mplot3d import Axes3D from matplotlib import pyplot as plt import numpy as np fig = plt.figure() ax = fig.add_subplot(111, projection='3d') def plot_bo(bo): # プロット範囲 X1 = [x1 for x1 in np.arange(x1_min, x1_max, 0.1)] X2 = [x2 for x2 in np.arange(x1_min, x2_max, 0.1)] X1, X2 = np.meshgrid(X1, X2) # サンプル点 xs1 = [bo.res[p]['params']['x1'] for p in range(len(bo.res))] xs2 = [bo.res[p]['params']['x2'] for p in range(len(bo.res))] ys = [bo.res[p]['target'] for p in range(len(bo.res))] ax.scatter(xs1,xs2, ys, c='black', s=20, zorder=10, label='sample') # 最大値 print(bo.max) max_x1 = bo.max['params']['x1'] max_x2 = bo.max['params']['x2'] max_y = bo.max['target'] print('max = ', max_x1, max_x2, max_y) for y in range(0, int(max_y)): #stick ax.scatter([max_x1],[max_x2], y , c='green', s=1) ax.scatter([max_x1],[max_x2],[max_y], c='green', s=100, zorder=10, label='pred_max') # 結果をグラフに描画する plot_bo(bo) # グラフを表示する plt.legend() plt.grid() plt.show() 数値(最適化した変数と最終資産額)だけほしい場合は,このプロット関数は削除して実行してください. このコードの参考はこちら 実行結果 上のコードをつなげて実行すると,以下のような結果が返ってきます. | iter | target | x1 | x2 | ------------------------------------------------- x1 : 10.113909909089411 x2 : 44.593196975228075 Equity : 2314.6739362205503 | 1 | 2.315e+0 | 10.11 | 44.59 | x1 : 12.257189040740247 x2 : 41.37558830835935 Equity : 2364.064460275459 | 2 | 2.364e+0 | 12.26 | 41.38 | …省略 x1 : 36.36372053777794 x2 : 15.116533268284256 Equity : 1008.9229018430711 | 99 | 1.009e+0 | 36.36 | 15.12 | x1 : 50.0 x2 : 47.13275305522422 Equity : 1469.4334687307353 | 100 | 1.469e+0 | 50.0 | 47.13 | ================================================= OPTIMIZE: END {'target': 3550.1827172409053, 'params': {'x1': 18.786763751511803, 'x2': 27.177235756482396}} max = 18.786763751511803 27.177235756482396 3550.1827172409053 グラフのx,y軸はx1,x2の値で,z軸が最終資産額です. また,緑の場所が最適解です. 短期SMAの日数x1 : 18日 長期SMAの日数x2 : 27日 最終資産額 : 3550 となりました. 2018年からの3年間で資産額が1000 → 3550ですから,さすがApple株!という感じです. この結果は2018年1月1日にApple株を買ってずっと持っていたときの資産額と同じかそれ以上くらいなので,谷と山をうまく利用した,なかなか良い結果だと言えるかもしれません. ちなみに,この日数でバックテストを行ったときの様子を描画すると以下のような感じです. Backtesting.pyのoptimize機能との比較 さて,これがどれくらいいい結果なのか?をBacktesting.pyのoptimize機能と比較してみていきたいと思います. Backtesting.pyでは,以下のように書くことで最終資産額を最適化できます.変数の範囲は先ほどと同じにしてあります(これを実行するには,こちらの記事をApple株に変え,cash=10000,最適化の際の日数間隔を1日にすると楽です). 手法は,グリッドサーチで探索します. #Backtesting.pyによる手法最適化 output2=bt.optimize(n1=range(1, 50, 10),n2=range(1, 50, 10), maximize='Equity Final [$]', method='grid') print(output2) bt.plot() 結果は以下のようになりました(コードによるの結果の一部だけ表示しています). method : grid 短期SMAの日数x1 : 11日 長期SMAの日数x2 : 21日 最終資産額 : 2838 なぜか,こちらの方が悪い結果になりました…(なぜ?) Backtesting.pyのドキュメントを読むと,以下のように書いてありました. "grid" which does an exhaustive (or randomized) search over the cartesian product of parameter combinations 「またはランダムに(or randomized)」と書いてあるので,もしかしたら全探索はしてないのかもしれません(よくわかりません). したがって,もう一つの最適化手法『skopt』を使ってみます. skoptは結局のところベイズ最適化を行っているみたいなので(参考),あまり比較にはならない気がしますが,ベイズ最適化の精度を確認する意味はあると思いますのでやってみます. skoptを使用するには,以下のインストールが必要です. pip install scikit-optimize 最適化の実行は,method以外は先ほどと同様です. #最適化 output2=bt.optimize(n1=range(1, 50, 10),n2=range(1, 50, 10), maximize='Equity Final [$]', method='skopt') print(output2) bt.plot() 結果は以下のようになりました. method : skopt 短期SMAの日数x1 : 19日 長期SMAの日数x2 : 23日 最終資産額 : 3489 最初に行ったベイズ最適化の結果と近い値がでました. MACDを最適化 今回は2本のSMAでバックテストを行い最適化しましたが,同様にして以下のようにMACDバージョンなどもできます. 反省 Apple株のような長期的に伸びている株でやって最終資産額を見てもあまり意味がない気がするので,もう少し変化が小さい株でやるか,他の指標を最大化する必要がありますね… 投資に関する免責事項 プログラムや考え方の情報の提供・作業代行を目的としており,投資勧誘を目的とするものではありません.また,この記事は投資成績を保証するものではありません.投資はあくまで自己責任でお願いします.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

量子化学入門 Roothaan SCF計算(続報)

前回の『量子化学入門 Roothaan SCF計算」で、最後の2中心電子間反発積分に関する部分を補足します。全くピッタリのページを発見しました。 2中心電子間反発積分の解法ページ <AB||AB> = <AB|\frac{1}{r_{12}}|AB> = \iintφ_{A1}φ_{B2}\frac{1}{r_{12}}φ_{A1}φ_{B2}dτ_1dτ_2 \\ = \intφ_{B2}φ_{B2}\left(\intφ_{A1}φ_{A1}\frac{1}{r_{12}}dτ_1\right)dτ_2 上記の2中心電子間反発積分を解いています。ただし解法ページでは、A1 と B2 にスレーター型関数を使っていますので、これをガウス型関数P1とQ2に、次のように置き換えるだけです。 φ_{A1}φ_{A1} = φ_{P1} \\ φ_{B2}φ_{B2} = φ_{Q2} つまり次の積分を解きます。 <P_1|\frac{1}{r_{12}}|Q_2> = \iintφ_{P1}\frac{1}{r_{12}}φ_{Q2}dτ_1dτ_2 \\ = \intφ_{Q2}\left(\intφ_{P1}\frac{1}{r_{12}}dτ_1\right)dτ_2 解法は上記の解法ページをそのまま使えます。 以上、簡単ですが補足の続報として。 ※ 一方、Sumuel Francis Boys が始めた 4 中心積分を 2 中心積分に変換する公式は、まだ元文を捜索中です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Pythonでリアルタイム演奏〜music21を使った実装〜

はじめに この記事は、音楽情報処理ライブラリmusic21の公式ドキュメントで紹介されているコードを実際に動かしてみて、日本語で詳しい解説をつけたり感想を書いたりしたものです。書いてて楽しくなってきちゃったのでソースコードの「全行解説」にも挑戦しました。 動機 皆さん、今やpythonでなんでもできると思ってますよね。僕もそう思っています。 人それぞれに作りたいものがあると思いますが、僕はずっとpythonで音楽を聞きたかった。 できたらいいなぁ程の気持ちで関連技術を勉強していたのですが、簡単に実装できるアイデアが公開されているのを先ほど見つけたので紹介します。 正直コピペなんですが、解説記事を書くことで自分の理解を深めたいなぁと思ってキーボードに向かっています。 環境 macOS(10.15.7) python3.8.5 jupyter-notebook music21とpygameがインストールしてあるpython環境 Music21について Music21は、MITから公開されている音楽情報処理に長けたpythonライブラリです。公式ドキュメントはこちら 音楽に関すること、特に楽譜で表現できることを扱うパワフルな機能が多数搭載されています。先日、概要を紹介した記事を書いたので気になる方はこちらもご覧になってください。 Pygameについて Music21はリアルタイム処理を専門としていません。そのため、ここで主に扱うオブジェクトであるmusic21.midi.realtimeはPygameに依存しています。環境にpygameを用意しておいてください。 早速動かしてみよう 何も考えないで公式ドキュメントからコピペして実行します。music21のimport文だけは追加で書いときます。 何が起こるのかは起こってから考えます。 from music21 import* import random keyDetune = [] for i in range(127): keyDetune.append(random.randint(-30, 30)) b = corpus.parse('bwv66.6') for n in b.flat.notes: n.pitch.microtone = keyDetune[n.pitch.midi] sp = midi.realtime.StreamPlayer(b) sp.play() 出力結果 音声が重要なので動画でご覧ください。 https://youtu.be/M7SP6j82pmI バッハだ!やったー! (僕の環境で実行した時はライブラリの依存先であるpygameが起動したときに色々主張してきたんですが、無視) コード全行解説 コード解説の前に 早速コードを一行ずつ見ていきたいところですが、その前に。 出力された音楽を聴いて、違和感を覚えた人がいるかと思います。 機械が出力する音楽にしては、ピッチが正確でないですね。 安心してください。これは技術の限界などではなく、コード側でわざわざ音程を狂わせてるんです。なんでそんなことを、と思いますが、次の段落で解説します。 全行解説は冗長かもしれませんが、結構コードを読むのに背景知識を使うので。 ピッチズレ配列の生成 keyDetune = [] for i in range(127): keyDetune.append(random.randint(-30, 30)) for文を使ってランダムに127個ズレの大きさ(最大±30cent)を設定しています。 定数127はMIDIのノートナンバーの総数ですね。数値ベタ書きはちょっと親切じゃないなと思いました。MIDIでは鍵盤の音に0~127の数を割り振っています。10オクターブ半+半音相当です。 つまるところこれは、ここで再現するピアノは各鍵盤がそれぞれちょっとズレてるよ、という配列です。バロック音楽を演奏する古楽器の雰囲気が出てるのかもしれません。知りません。30centもズレてることあるんですか? (なお、DTMにはdetuneというテクニックがあるようです(参考)) courpus b = corpus.parse('bwv66.6') music21の誇る強力な曲データベース、corpusからバッハの曲を取得します。 主にクラシックの楽譜が多数収録されており、中身の音符のデータとかもいじれます。 parseメソッドが返す曲オブジェクトはmusic21.stream.Scoreオブジェクトと言います。 bwvというのはバッハ作品主題目録番号のことです。バッハの曲が一意に特定できます。 for n in b.flat.notes: n.pitch.microtone = keyDetune[n.pitch.midi] 曲中の全ての音符(note) オブジェクトにアクセスして、microtoneプロパティに先ほど作ったピッチズレを代入。KeyDetune配列のキーがMIDI番号になってるのがミソですね flatプロパティ さて、b.flat.notesという部分が気になる方もいるかもしれません。flatというのは、入れ子構造になっているstreamを全て展開して読み取りやすくした新たなstreamを返してくれる読み込み専用プロパティです。 例を挙げるために、簡単な2声の楽譜を用意します。(公式ドキュメントからコピペ) パートが二つあっても、一つのscoreオブジェクトに格納できます。 sc = stream.Score() p1 = stream.Part() p1.id = 'part1' n1 = note.Note('C4') n2 = note.Note('D4') p1.append(n1) p1.append(n2) p2 = stream.Part() p2.id = 'part2' n3 = note.Note('E4') n4 = note.Note('F4') p2.append(n3) p2.append(n4) sc.insert(0, p1) sc.insert(0, p2) 作ったscoreオブジェクトの要素を見てみましょう sc.elements (<music21.stream.Part part1>, <music21.stream.Part part2>) sc直下にあるのはstream.Partオブジェクトだけです。'E4'などのNoteオブジェクトはさらに下層にあるので、elementプロパティからは直接みえないんですね〜。 だから、このままflatプロパティを使わずに下層オブジェクトに触れようと思ったらこう書く必要があります。 sc[0].elements (<music21.note.Note C>, <music21.note.Note D>) もしくは、 sc.getElementById('part2').elements (<music21.note.Note E>, <music21.note.Note F>) こういうのが面倒くさいので、flatプロパティが存在しています。 sc.flat.elements (<music21.note.Note C>, <music21.note.Note E>, <music21.note.Note D>, <music21.note.Note F>) 入れ子構造がすっきりしましたね。 こいつのおかげで、前述のfor文の中にNoteオブジェクトを簡単に渡せるってワケです。 StreamPlayer こいつが今回の「演奏」部分の核ですね。 sp = midi.realtime.StreamPlayer(b) sp.play() そんなに言うことはないです。 corpasから持ってきたオブジェクトを渡して、pc上で演奏してくれてます。カンタン! 渡すオブジェクトはstreamである必要があります。 終わりに MITのドキュメントがめちゃくちゃ丁寧なおかげで、全行解説とかいう無茶も一応やり切ることができました。 music21で遊びたい時は、公式ドキュメントを読むことを強くお勧めします。 このmusic21ライブラリはあくまで「楽曲分析」のためのものであって、演奏機能はおまけに過ぎません。 それなのにここまでのことができるのはさすがMITと言わざるを得ませんが、演奏機能をメインに据える何かを開発したいなら、他のライブラリも調べた方が良さそうです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DCGANとPGGANを習得したお話-アニメキャラクター画像を生成するまでの過程

はじめに mnist手書き文字を生成するチュートリアルから、実際に256x256pixの高精度画像を作るまでの過程をまとめた記事です。 DCGANの実装にはkerasを用います。 PGGANの実装にはpytorchを用います。 実装難易度はかなり高めなはずなので、そこだけ注意してください。 計算式の解説はしません。キーワードだけ置いておくので、うまく調べて理解してください。 この記事は他の寄稿者への恩返しの記事です。この記事を読んで、GANに興味を持つ方が増えていくことを私は願っています。 この長い長い記事の最終地点はこのような製品に行きつきます。 前提 python (目安としてクラスまで) keras (画像識別モデルを自由に作れるくらい) pytorch (上に同じく)(私はGANのために習得した) numpy (調べて使えれば大丈夫です) GANの基礎知識 諦めない心 (最重要) 時間 環境 推奨: colab環境 つよつよGPU持ってるならそれでも可 注意点 ・もう一度言いますが初学者が踏み込んでいい領域じゃないです。 ・一回のモデルの学習に多大な時間がかかります ・どこかミスると1日2日は無駄になります。コピペするなら堂々としてください。 ・GANは不安定なので、うまくいかないことの方が多いです。 ・病みます。ほどほどに。 GANの説明 GANとは Generative Adversarial Network(敵対的生成ネットワーク)の略語 GANは、虚無から画像を生み出すことができるすごいやつ 構造はこんな感じ GはGenerator(生成機)、DはDiscriminator(識別機)の略です zはノイズ(数学的にはベクトル)です Xは教師データのことです Gはノイズを基に画像を生成 Dは本物の画像(X)とfake画像(G(z))を判別する 誤差をGとDに伝える 一番上から繰り返す こうすると、GはDをだませるような画像を生成できるようになっていきます。 GとDは互いに成長していくので、精度が少しずつ向上していくわけです。 このやりとりは、偽札を作る犯罪者とそれを見破る警察にたとえられます。 DCGANの仕組み DCGANはGANのGとDに対して、CNNの構造を取り入れたネットワークです。 ほかの発展形のGANの祖と言える存在です。 最適化関数は一般的にAdam、lossは平均二乗誤差 普通ですね(白目) 基本構造は上の画像の通り。解像度を少しずつ上げていく転置畳み込みをしています イメージです。0となっている部分にも値を当てはめる処理をすることもあるみたい 私からのDCGANの説明は以上です。いろいろ端折ってるのでわからないところは調べてください(他力本願) PGGANの仕組み PGGANは、低解像度から段階的に解像度を上げて、高解像度の画像を生成するGANです。 段階的に解像度を上げる仕組みのおかげで、安定して高解像度の画像を生成することに成功しています。DCGANでは解像度64x64程度が限度でしたが、PGGANでは解像度1024x1024まで生成することが可能です。 PGGANにはPixelwisenormalization、MinibatchStd、WGAN-GP loss、equalizedrateなどの工夫が施されているが、詳しい解説は省く(後述のソースコードには実装されている) こういったサイトに解説が載っている。式が絡むのでここで詰むくらいならおとなしくコピペすることをお勧めする。 https://blog.negativemind.com/2020/06/27/progressive-growing-gan/ 今回の演習は256x256の解像度で行います。 その他の主要なGAN cGAN 条件付きGAN、画像の特徴をある程度決めて生成できる。どのGANにも組み込める styleGAN 現状(2021/4/9)で最も自然で高精度な画像を生成できる。また、学習データ間に共通点がなくても高精度で生成できる(例として猫の画像と、人間の画像どちらを作るか指定して同じモデルで生成できる) ただし一般的に学習コストが非常に重い。数千万円のGPU数機を動かしてようやくまともに学習できるほどなので、一般人は触れる機会すらない。 cycleGAN 二つのGAN構造を組み合わせて作られたモデル。deepfakeなどの技術に応用されている。 実装と考察 学習を始める前の注意点 GANの学習は不安定なので、Generatorが突然不安定な画像ばかり生成するようになることがある。ここではその事例を見ていく。 Mode Collapse GANには通常のn値分類モデル学習で発生するような勾配消失問題の代わりとして、同じ画像しか生成しなくなる現象が報告されている。 上記は0~9の画像を生成するはずのモデルだったはずが、1と8しか出さなくなっている。 この現象が起きる理由は意外に単純で、1と8さえ出しとけばdiscriminatorをより楽にだませるということをGeneratorが知ってしまい怠けてしまっているような状態をになっている。 この現象は開発する際の大きな障壁となるので、しっかり覚えておいたほうがいい。すべてのGANで起こりうる問題である。例外はあるが、これが起こってしまう原因として、学習率が高すぎることがあげられることがある。予兆はなく突然起こるので、対策は容易ではない。PGGANの実装では、一応対策してあるのでその点はご心配なく。 Discriminator強すぎ問題 discriminatorが強すぎると、generatorがdiscriminatorの学習速度に追いつかず、学習が崩壊してしまう。一般的に、単に2値分類であるdiscriminatorのほうが強くなりやすい性質があるため、discriminatorのモデルをあえて弱くするなどして対応することがある。 今回実装するPGGANでは、この問題は起こらない。そもそもPGGANはこの問題の解決のために生み出されたものである。この問題は最高精度に大きく関わってくる。 強力な追加手法 GANの論文などで多く紹介される強化手法を紹介します ・ノイズには一様分布ではなく、正規分布を使うこと ・Reluの代わりにLeakyRelu(alpha=0.2)を使うこと ・最適化手法はAdam一択 ・学習がうまくいかないからと言って、人為的介入をしないこと kerasでmnist手描き文字を使ったチュートリアル(DCGAN) この演習では、DCGANを使います。簡単な方です。 colab環境前提でコードを書きます。環境が違う方は適時頑張って対応してください。 また、pathなども自身で合わせていただけると幸いです。コードは読みづらいかもです。 今回はよくあるmnist+DCGANの実装と、筆者の気分でresnetによる実装の両方を用意しました。resnetを使っているipynbファイルはgithubに上げてあるのでそちらを参照ください。 実装 #colab環境にgdriveをマウント from google.colab import drive drive.mount('/content/drive') #mnist手書き文字のデータセットの用意と軽い準備 import numpy as np from keras.datasets import mnist import cv2 (X_train, y_train), (X_test, y_test) = mnist.load_data() #-1~+1に正規化 X_train = (X_train.astype(np.float32) - 127.5)/127.5 #チュートリアル from __future__ import print_function, division from keras.datasets import mnist from keras.layers import Input, Dense, Reshape, Flatten, Dropout,Reshape,Add from keras.layers import BatchNormalization, Activation, ZeroPadding2D,MaxPooling2D,GlobalAveragePooling2D from keras.layers.advanced_activations import LeakyReLU from keras.layers.convolutional import UpSampling2D, Conv2D from keras.models import Sequential, Model from keras.optimizers import Adam import cv2 import matplotlib.pyplot as plt import sys import numpy as np class DCGAN(): def __init__(self): # Input shape self.input_img_rows = 28 self.input_img_cols = 28 self.input_channels = 1 self.input_img_shape = (self.input_img_rows, self.input_img_cols, self.input_channels,) self.latent_dim = 100 optimizer = Adam(0.00001, 0.5) # 2値分類のための識別モデルを作成 self.discriminator = self.build_discriminator() self.discriminator.compile(loss='binary_crossentropy', optimizer=optimizer, metrics=['accuracy']) # Build the generator self.generator = self.build_generator() z = Input(shape = self.latent_dim) img = self.generator(z) # discriminatorのパラメータ固定 self.discriminator.trainable = False valid = self.discriminator(img) self.combined = Model(z, valid)#並列結合 self.combined.compile(loss='binary_crossentropy', optimizer=optimizer) def build_generator(self): model = Sequential() model.add(Dense(512*7*7, input_shape=[self.latent_dim])) model.add(Reshape((7,7,512))) model.add(LeakyReLU(alpha=0.2)) model.add(BatchNormalization(momentum=0.8)) model.add(Conv2D(512, kernel_size=3, strides=1, padding="same")) model.add(LeakyReLU(alpha=0.2)) model.add(BatchNormalization(momentum=0.8)) model.add(Conv2D(256, kernel_size=3, strides=1, padding="same")) model.add(UpSampling2D((2,2))) model.add(LeakyReLU(alpha=0.2)) model.add(BatchNormalization(momentum=0.8)) model.add(Conv2D(256, kernel_size=3, strides=1, padding="same")) model.add(LeakyReLU(alpha=0.2)) model.add(BatchNormalization(momentum=0.8)) model.add(Conv2D(128, kernel_size=3, strides=1, padding="same")) model.add(UpSampling2D((2,2))) model.add(LeakyReLU(alpha=0.2)) model.add(BatchNormalization(momentum=0.8)) model.add(Conv2D(128, kernel_size=3, strides=1, padding="same")) model.add(LeakyReLU(alpha=0.2)) model.add(BatchNormalization(momentum=0.8)) model.add(Conv2D(128, kernel_size=3, strides=1, padding="same")) model.add(Dense(self.input_channels)) model.add(Activation('tanh')) #-1 ~ 1 に分散してくれるやつ model.summary() img = Input(shape=self.latent_dim) validity = model(img) return Model(img,validity) def build_discriminator(self): model = Sequential() model.add(Conv2D(512, kernel_size=3, strides=1, input_shape=self.input_img_shape, padding="same")) model.add(LeakyReLU(alpha=0.2)) model.add(Conv2D(256, kernel_size=3, strides=1, input_shape=self.input_img_shape, padding="same")) model.add(LeakyReLU(alpha=0.2)) #model.add(BatchNormalization(momentum=0.8)) model.add(Conv2D(128, kernel_size=3, strides=1, padding="same")) model.add(LeakyReLU(alpha=0.2)) model.add(Conv2D(64, kernel_size=3, strides=1, padding="same")) model.add(LeakyReLU(alpha=0.2)) model.add(Flatten()) model.add(Dense(1, activation='sigmoid')) model.summary() img = Input(shape=self.input_img_shape) validity = model(img) return Model(img, validity) def train(self, epochs, batch_size=128, save_interval=500): print("実行1") # Adversarial ground truths valid = np.ones((batch_size, 1)) fake = np.zeros((batch_size, 1)) #コンスタントなノイズ imagegennoise = np.random.uniform(-1, 1, (32,self.latent_dim)) for epoch in range(epochs): # 本物の画像をbatchの数だけランダムで持ってきます idx = np.random.randint(0, len(X_train), batch_size) true_imgs = X_train[idx] # batchの数だけノイズを生成し、generatorに画像を生成させる noise = np.random.normal(0, 1, (batch_size, self.latent_dim)) gen_imgs = self.generator.predict(noise) # 本物の画像とフェイク画像を識別機に学習させます。 d_loss_real = self.discriminator.train_on_batch(true_imgs, valid) d_loss_fake = self.discriminator.train_on_batch(gen_imgs, fake) d_loss = 0.5 * np.add(d_loss_real, d_loss_fake) # 誤差を伝搬させて、generatorを学習させます g_loss = self.combined.train_on_batch(noise, valid) print ("%d [D loss: %f, acc.: %.2f%%] [G loss: %f]" % (epoch, d_loss[0], 100*d_loss[1], g_loss)) if epoch % 50 == 0: testimg = self.generator.predict(imagegennoise) dst = np.array((testimg * 0.5 + 0.5) * 255, np.int32) #0~255(人間に見やすく) #32,28,28,1 dst = dst.reshape(4,8,1,28,28) dst = dst.transpose(0,3,1,4,2) dst = dst.reshape(4*28,8*28,1) cv2.imwrite(f'/content/drive/MyDrive/GANstudy/2.12/createimages/test{str(epoch)}.jpg', dst) if __name__ == '__main__': dcgan = DCGAN() dcgan.train(epochs=100000, batch_size=128, save_interval=500) 長いですね...重要なところだけ上から順に説明していきます。 import類 いるものを適当に入れてるだけ。多分余計なのも入ってる。若干コピペだから許してください。 init関数 画像のサイズとか指定してます。 GeneratorとDiscriminatorを定義して、コンパイルしてます。このあたりは、筆者自身過去に変な説明を受けて、理解が余計難しくなったので、今回はあえて解説はしません。コードを読んで理解するほうが早いのでそちらをお勧めします。 self.latent_dim = 100 この部分はほかのサイトでも見たことがある人もいると思いますが、100次元のノイズのことを表しています。ノイズについての説明は後で行います。 build_generator関数 generatorモデルを作成するための関数 model.add(Conv2D(256, kernel_size=3, strides=1, padding="same")) model.add(UpSampling2D((2,2))) この部分がいわゆる転置畳み込みの部分である。転置畳み込みは、簡単に言えばレイヤー数を下げて、特徴量マップを増やす処理である。この処理をすることで、100次元のノイズから28x28x1の一枚の画像までもっていくことが可能になる。 model.add(Dense(self.input_channels)) model.add(Activation('tanh')) #-1 ~ 1 に分散してくれるやつ 画像のチャンネル数は黒or白の一色なので、レイヤーの数を1(self.input_channelsは1)にして、28x28x1の特徴マップを作っている。(RGBを出力したいなら3になる) 画像を出力する必要があるので、出力層には-1~1を出力できる、tanh関数を使用する。 build_discriminator関数 この部分はただのCNNなので説明は省きます。強いて言うならleakyReluを使っているだけです。 train関数 学習する部分の関数 正直一個一個紹介していたらきりがないので、コードを読んで理解してください。 私はコピペしたので普通にコピペだけして理解しなくても構わないかと思います。そこまで重要なことは書いてないです。 結果と考察 まずこのモデルを動かしたときの結果から紹介します 上から順に0,500,2000,5000,18000です 5000と18000あんまり差がないですよね、これ実は精度自体の差がほぼないです。 モデルがくそ雑魚なので、限界がこんなものという感じですね ちなみにgithubに公開されてるresnetの例では30000epoch目で このくらいの精度を出せます。おそらくこれくらいが極限に近い精度です。 GANにはresnetが刺さりやすいです。 pytorchで本格的な生成モデルを作ってみよう(PGGAN) この演習では、PGGANを使います。難しい方です。 正直なことを言うと、筆記時点での私の実力はここが限界なので、詳しい解説はできません。ただし、実装成功はしているので、参考になればと思います。PGGANの実装に成功している記事はほとんどないので、きっとこれだけでも誰かの役に立つと信じます。 まずはデータセットを収集します。 今回は以下のデータセットを使用しました。 https://www.kaggle.com/scribbless/another-anime-face-dataset ときどき、明らかに使えないデータが混ざっているため、データの選別をする必要があるかもしれません。私は手動で30時間かけて90000枚すべての画像を見ました。3000枚くらいはごみデータでした。精度を上げるにはデータの選別は必須なので頑張りましょう。 厳しいよって方は人間の顔画像を使うといいでしょう。GAN 顔画像 とでも調べると、名前を忘れてしまいましたが高解像度の人間の顔画像のデータセットがヒットします。 人間の顔画像をGANで生成することは想像以上に容易なので、練習するならそっちでやるのをお勧めします。 次に、集めてきたデータを256x256(ここは任意のサイズで大丈夫ですが2の倍数が好ましいです)にreshapeしてまとめておきましょう。 そして、googledriveに収集したデータをzip形式でまとめて置いておきましょう。 ここまでの話を理解できない方はこの先に進むことをお勧めしません。応用力がためされる内容になっているので、無駄足の可能性があります。 以下、コードです。解説はありません。 from google.colab import drive drive.mount('/content/drive') !cp "/content/drive/My Drive/animefacemini.zip" . !unzip "animefacemini.zip" モデル定義 import torch from torch import nn from torch.nn import functional as F import torchvision import torchvision.transforms as transforms import cv2 import numpy as np import random from time import sleep # PixelNormalization Module class PixelNorm(nn.Module): # 修正点1 def forward(self, x): eps = 1e-8 return x / ((torch.mean(x**2, dim=1, keepdim=True) + eps) ** 0.5) # equalized larning rate class WeightScale(nn.Module): # 修正点2 def forward(self, x, gain=2): c = ( (x.shape[1] * x.shape[2] * x.shape[3]) / 2) **0.5 return x / c # バッチの多様性を考慮 class MiniBatchStd(nn.Module): def forward(self, x): std = torch.std(x, dim=0, keepdim=True) mean = torch.mean(std, dim=(1,2,3), keepdim=True) n,c,h,w = x.shape mean = torch.ones(n,1,h,w, dtype=x.dtype, device=x.device)*mean return torch.cat((x,mean), dim=1) # 畳み込み処理回りが煩雑だからモジュール化 class Conv2d(nn.Module): def __init__(self, inch, outch, kernel_size, padding=0): super().__init__() self.layers = nn.Sequential( WeightScale(), nn.ReflectionPad2d(padding), nn.Conv2d(inch, outch, kernel_size, padding=0), ) nn.init.kaiming_normal_(self.layers[2].weight) #Heの初期化 def forward(self, x): return self.layers(x) class ResBlock(nn.Module): def __init__(self, inch, outch, kernel_size, padding=0): super().__init__() self.conv1 = Conv2d(inch, outch, 3, padding=1) self.relu1 = nn.LeakyReLU(0.2, inplace=False) self.pixnorm1 = PixelNorm() self.conv2 = Conv2d(outch, outch, 3, padding=1) self.relu2 = nn.LeakyReLU(0.2, inplace=False) self.pixnorm2 = PixelNorm() self.relu3 = nn.LeakyReLU(0.2, inplace=False) self.shortcut = nn.Conv2d(inch, outch, kernel_size=(1, 1), padding=0) def forward(self, x): h = self.conv1(x) h = self.relu1(h) h = self.pixnorm1(h) h = self.conv2(h) h = self.relu2(h) h = self.pixnorm2(h) x = self.shortcut(x) y = self.relu3(h + x) return y # Generatorの連結モデルを定義 class ConvModuleG(nn.Module): ''' Args: out_size: (int), Ex.: 16 (resolution) inch: (int), Ex.: 256 outch: (int), Ex.: 128 ''' def __init__(self, out_size, inch, outch, first=False): super().__init__() if first: layers = [ Conv2d(inch, outch, 3, padding=1), nn.LeakyReLU(0.2, inplace=False), PixelNorm(), Conv2d(outch, outch, 3, padding=1), nn.LeakyReLU(0.2, inplace=False), PixelNorm(), ] else: layers = [ nn.Upsample((out_size, out_size), mode='nearest'), Conv2d(inch, outch, 3, padding=1), nn.LeakyReLU(0.2, inplace=False), PixelNorm(), Conv2d(outch, outch, 3, padding=1), nn.LeakyReLU(0.2, inplace=False), PixelNorm(), ] self.layers = nn.Sequential(*layers) def forward(self, x): return self.layers(x) class ConvModuleD(nn.Module): ''' Args: out_size: (int), Ex.: 16 (resolution) inch: (int), Ex.: 256 outch: (int), Ex.: 128 ''' def __init__(self, out_size, inch, outch, final=False): super().__init__() if final: layers = [ MiniBatchStd(), # final block only Conv2d(inch+1, outch, 3, padding=1), nn.LeakyReLU(0.2, inplace=False), PixelNorm(), Conv2d(outch, outch, 4, padding=0), nn.LeakyReLU(0.2, inplace=False), PixelNorm(), nn.Conv2d(outch, 1, 1, padding=0), ] else: layers = [ Conv2d(inch, outch, 3, padding=1), nn.LeakyReLU(0.2, inplace=False), PixelNorm(), Conv2d(outch, outch, 3, padding=1), nn.LeakyReLU(0.2, inplace=False), PixelNorm(), nn.AdaptiveAvgPool2d((out_size, out_size)), ] self.layers = nn.Sequential(*layers) def forward(self, x): return self.layers(x) class Generator(nn.Module): def __init__(self): super().__init__() # conv modules & toRGBs scale = 1 inchs = np.array([512/16,512,512,512,512,256,128], dtype=np.uint32)*scale # inputするレイヤー数(追加分) outchs = np.array([512,512, 512,512,256,128,64], dtype=np.uint32)*scale # outputするレイヤー数(追加分) sizes = np.array([4,8,16,32,64,128,256], dtype=np.uint32) firsts = np.array([True, False, False, False, False, False,False], dtype=np.bool) blocks, toRGBs = [], [] for s, inch, outch, first in zip(sizes, inchs, outchs, firsts): blocks.append(ConvModuleG(s, inch, outch, first)) toRGBs.append(nn.Conv2d(outch, 3, 1, padding=0)) self.blocks = nn.ModuleList(blocks) self.toRGBs = nn.ModuleList(toRGBs) def forward(self, x, res, eps=1e-7): # to image n,c = x.shape x = x.reshape(n,c//16,4,4) # for the highest resolution res = min(res, len(self.blocks)) # get integer by floor nlayer = max(int(res-eps), 0) #print(res,nlayer) for i in range(nlayer): x = self.blocks[i](x) # high resolution x_big = self.blocks[nlayer](x) dst_big = self.toRGBs[nlayer](x_big) if nlayer==0: x = dst_big else: # レイヤー変更時の負荷軽減 # low resolution x_sml = F.interpolate(x, x_big.shape[2:4], mode='nearest') dst_sml = self.toRGBs[nlayer-1](x_sml) alpha = res - int(res-eps) #print(alpha) x = (1-alpha)*dst_sml + alpha*dst_big #return x, n, res return torch.sigmoid(x) class Discriminator(nn.Module): def __init__(self): super().__init__() self.minbatch_std = MiniBatchStd() # conv modules & toRGBs scale = 1 inchs = np.array([512,512,512,512,256,128,64], dtype=np.uint32)*scale outchs = np.array([512,512, 512,512,512, 256,128], dtype=np.uint32)*scale sizes = np.array([1,4,8,16,32,64,128], dtype=np.uint32) finals = np.array([True, False, False, False, False, False,False], dtype=np.bool) blocks, fromRGBs = [], [] for s, inch, outch, final in zip(sizes, inchs, outchs, finals): fromRGBs.append(nn.Conv2d(3, inch, 1, padding=0)) blocks.append(ConvModuleD(s, inch, outch, final=final)) self.fromRGBs = nn.ModuleList(fromRGBs) self.blocks = nn.ModuleList(blocks) def forward(self, x, res): # for the highest resolution res = min(res, len(self.blocks)) # get integer by floor eps = 1e-8 n = max(int(res-eps), 0) # high resolution x_big = self.fromRGBs[n](x) x_big = self.blocks[n](x_big) if n==0: x = x_big else: # low resolution x_sml = F.adaptive_avg_pool2d(x, x_big.shape[2:4]) x_sml = self.fromRGBs[n-1](x_sml) alpha = res - int(res-eps) x = (1-alpha)*x_sml + alpha*x_big for i in range(n): x = self.blocks[n-1-i](x) return x def gradient_penalty(netD, real, fake, res, batch_size, gamma=1): device = real.device alpha = torch.rand(batch_size, 1, 1, 1, requires_grad=True).to(device) x = alpha*real + (1-alpha)*fake d_ = netD.forward(x, res) g = torch.autograd.grad(outputs=d_, inputs=x, grad_outputs=torch.ones(d_.shape).to(device), create_graph=True, retain_graph=True,only_inputs=True)[0] g = g.reshape(batch_size, -1) return ((g.norm(2,dim=1)/gamma-1.0)**2).mean() 学習 #写真数90000 if __name__ == '__main__': device = 'cuda' if torch.cuda.is_available() else 'cpu' #Gparam = torch.load('/content/drive/MyDrive/GANstudy/PGGAN/models5/6-netG.pth') netG = Generator().to(device) try: netG.load_state_dict(Gparam,strict=False) except: pass netD = Discriminator().to(device) netD.load_state_dict(torch.load('/content/drive/MyDrive/GANstudy/PGGAN/models5/6-netD.pth')) #Gparam = torch.load('/content/drive/MyDrive/GANstudy/PGGAN/models5/6-netG_mavg.pth') netG_mavg = Generator().to(device) # moving average try: netG_mavg.load_state_dict(Gparam,strict=False) except: pass lr = 0.001 optG = torch.optim.Adam(netG.parameters(), lr = lr, betas=(0.0, 0.99)) optD = torch.optim.Adam(netD.parameters(), lr = lr, betas=(0.0, 0.99)) criterion = torch.nn.BCELoss() batch_size = 4 # dataset transform = transforms.Compose([transforms.ToTensor(),transforms.Resize((256,256))]) trainset = torchvision.datasets.ImageFolder(root="/content/animefacemini", transform=transform) train_loader = torch.utils.data.DataLoader(trainset, batch_size=batch_size, shuffle=True, drop_last=True) # training res_steps = [30000,30000,30000,50000,100000,200000,500000 #[4,8,16,32,64,128,256] losses = [] j = 9873200 #学習深度-pixあたり res_i = 6 # 学習深度-pix nepoch = 3000 res_index = 6 #学習深度-pix # constant random inputs r = random.randint(0,99999999999) torch.manual_seed(256) z0 = torch.randn(16, 512).to(device) #16次元のconstノイズをn個排出 z0 = torch.clamp(z0, -1.,1.) torch.manual_seed(r) beta_gp = 10.0 beta_drift = 0.001 #lr_decay=0.87 #レイヤー変更時の減衰 # attenuation_rate = 0.99 #lr減衰率 #attenuation_timing = 200 #この回数ごとに減衰する(lossの値を監視して規定以上なら) torchvision.datasets.ImageFolder for iepoch in range(nepoch): for i, data in enumerate(train_loader): x, y = data x = x.to(device) res = ((j/res_steps[res_index]) * 1.25 + res_i) res = min(res,res_i+1) ### train generator ### z = torch.randn(batch_size, 512).to(x.device) x_ = netG.forward(z, res) del z d_ = netD.forward(x_, res) # fake lossG = -d_.mean() # WGAN_GP del d_ optG.zero_grad() lossG.backward() optG.step() # update netG_mavg by moving average momentum = 0.995 # remain momentum alpha = min(1.0-(1/(j+1)), momentum) for p_mavg, p in zip(netG_mavg.parameters(), netG.parameters()): p_mavg.data = alpha*p_mavg.data + (1.0-alpha)*p.data ### train discriminator ### z = torch.randn(x.shape[0], 512).to(x.device) x_ = netG.forward(z, res) del z x = F.adaptive_avg_pool2d(x, x_.shape[2:4]) d = netD.forward(x, res) # real d_ = netD.forward(x_, res) # fake loss_real = -1 * d.mean() loss_fake = d_.mean() loss_gp = gradient_penalty(netD, x.data, x_.data, res, x.shape[0]) loss_drift = (d**2).mean() del d_ del d lossD = loss_real + loss_fake + beta_gp*loss_gp + beta_drift*loss_drift optD.zero_grad() lossD.backward() optD.step() print('ep: %02d %04d %04d lossG=%.10f lossD=%.10f' % (iepoch, i, j, lossG.item(), lossD.item())) losses.append([lossG.item(), lossD.item()]) j += 1 #解像度の切り替わり条件 if res_steps[res_index] == j: PATH = "/content/drive/MyDrive/GANstudy/PGGAN/models5/" torch.save(netG.state_dict(), PATH + f"{res_index}-last-netG.pth") torch.save(netD.state_dict(), PATH + f"{res_index}-last-netD.pth") torch.save(netG_mavg.state_dict(), PATH + f"{res_index}-last-netG_mavg.pth") j = 0 res_index += 1 res_i += 1 if j%50 == 0: try: sleep(1) netG_mavg.eval() z = torch.randn(16, 512).to(x.device) z = torch.clamp(z, -1.,1.) x_0 = netG_mavg.forward(z0, res) x_ = netG_mavg.forward(z, res) dst = torch.cat((x_0, x_), dim=0) del z,x_0,x_ dst = F.interpolate(dst, (256, 256), mode='nearest') dst = dst.to('cpu').detach().numpy() n, c, h, w = dst.shape dst = dst.reshape(4,8,c,h,w) dst = dst.transpose(0,3,1,4,2) dst = dst.reshape(4*h,8*w,3) dst = np.clip(dst*255., 0, 255).astype(np.uint8) dst = cv2.cvtColor(dst, cv2.COLOR_BGR2RGB) cv2.imwrite(f'/content/drive/MyDrive/GANstudy/PGGAN/images5/image{res_index}-{j}-.jpg', dst) netG_mavg.train() except: print("error") if j%100 == 0: PATH = "/content/drive/MyDrive/GANstudy/PGGAN/models5/" torch.save(netG.state_dict(), PATH + f"{res_index}-netG.pth") torch.save(netD.state_dict(), PATH + f"{res_index}-netD.pth") torch.save(netG_mavg.state_dict(), PATH + f"{res_index}-netG_mavg.pth") if j%5000 == 0: PATH = "/content/drive/MyDrive/GANstudy/PGGAN/models5/" torch.save(netG.state_dict(), PATH + f"{res_index}-{j}-netG.pth") torch.save(netD.state_dict(), PATH + f"{res_index}-{j}-netD.pth") torch.save(netG_mavg.state_dict(), PATH + f"{res_index}-{j}-netG_mavg.pth") 解説がなくて申し訳ないです。pathは各自入れ替えてください。 ちなみにこの実装は論文で実装されていた構成のほぼ丸パクリです。 一応個人的にぐちゃぐちゃになっている学習のところだけ解説します jは学習深度。初期値0 res_i,res_indexはどの解像度にいるか。初期値0 res_stepsは各解像度でどれくらいの回数学習するかを決めてます。 batch_sizeはコード上は4ですが、初期値は256とかです。メモリに乗らなくなったら減らしていく感じです。 lrも初期値は0.001ですが、解像度が上がっていくにつれて不安定になっていくので、手動で減らしていきます。 学習に時間がかかるため、定期的にモデルの保存をしてます。colabでやる以上必須です。 コードを見ればわかると思いますが、ノイズ(ベクトル)は512次元です。 正直この辺りはPGGAN githubと調べて、すでに実装しやすいように準備されているコードを使ったほうがいいです。自由度こそ下がりますが、普通に実装しようとすると意味が分からないくらい難易度が高いのでお勧めしません。 結果と考察 先ほど紹介したデータセットでの学習成果を紹介 ...一見すると失敗してるように見えますよね。ではここからある技を使ってこのモデルを使えるようにしていきましょう 精度向上の秘密 結果から言います。 これくらいのレベルの画像がほとんどになるほど精度向上します。 まずこの精度向上の秘密を語るためには、まずはベクトル移動について学ぶ必要があります。 ベクトル移動 先ほどからノイズzという謎の存在をモデル内に入れていましたが ノイズzというのは数学的なベクトルと同意だと思ってください。 数学味がありますが、意外に単純なのでご安心を。 ベクトルという存在について超簡単に説明するなら、 「消しゴムがあります。消しゴムは白いです。消しゴムは鉛筆で描いた文字を消すことができます。なので消しゴムは『白色』と『消す』ベクトルを持っています」 「消しゴムは「白い」です。雲も「白い」です。ですが、雲は「消す」をもっていません なので、消しゴムと雲は同じものではないですが、ベクトル的には近しい部分があります」 このような、そのものが持つ抽象的な要素、特性を数値化したものを「ベクトル」といいます。 そしてこれがどう関係するのかというと、GANの内部構造と関係しています。GANの内部では、画像が持つ特徴量を抽出して、保存する動きがあります。 「髪の毛の色」「顔の向き」「目の色」「目の形」...数えられないくらい沢山の要素があり、それらの特徴を与えられたベクトルzをもとに結果を出していくという構造をしています。 この部分に関しては以下の記事が参考になるのでぜひこちらのほうをご覧ください。非常にわかりやすい記事になっています。 GANについて概念から実装まで ~DCGANによるキルミーベイベー生成~ 小難しい話は抜きにして、とりあえずこれをご覧ください。 この画像群は全てPGGANで作成されたものです。 画像が動いてますよね。これは内部的にはただベクトルzが動いてるだけで、PGGANは単純にベクトルに応じたデータを返しているだけです。 少しわかりにくいかもしれませんが、ベクトル演算をすることで、複数の画像の間の画像を生成できます。 そしてこれができるとなぜ精度が高くなるのかについて話を戻します。先程お見せしたキャラクター複数人の画像、ありましたよね。あの状態でそのまま出すの あまりよろしくないので、とりあえず「使える画像のベクトル」をなんらかの形で保存しておきます。 ベクトル検索、保存の仕方はなんでも構いません。私は眼で見て綺麗に作れてるなと思った画像のseed値をメモ帳に書き出して保存してました。多分この辺りも機械学習で自動化できます。 一応私が使っていたコードを置いておきます。pytorchです。 #checkimgs/shift-img-{seed}~{seed+30}.jpgとして保存 #複数枚のランダム画像 device = 'cuda' if torch.cuda.is_available() else 'cpu' width = 10 height = 3 netG_mavg = Generator().to(device) # moving average netG_mavg.load_state_dict(torch.load('/content/drive/MyDrive/GANstudy/PGGAN/models5/5-last-netG_mavg.pth')) optG = torch.optim.Adam(netG_mavg.parameters(), lr=0.001, betas=(0.0, 0.99)) def visualizeInterpolation(s): vectors = [] #値をすこしずつshift for mis in range(s,s+30): np.random.seed(seed=mis) z = np.random.randn(512) vectors.append(z) vectors = np.array(vectors) vectors = torch.from_numpy(vectors.astype(np.float32)).to(device) vectors = torch.clamp(vectors, -1.,1.) netG_mavg.eval() dst = netG_mavg.forward(vectors, 6) dst = F.interpolate(dst, (256, 256), mode='nearest') dst = dst.to('cpu').detach().numpy() n, c, h, w = dst.shape dst = dst.reshape(height,width,c,h,w) dst = dst.transpose(0,3,1,4,2) dst = dst.reshape(height*h , width*w , 3) dst = np.clip(dst*255., 0, 255).astype(np.uint8) dst = cv2.cvtColor(dst, cv2.COLOR_BGR2RGB) cv2.imwrite(f'/content/drive/MyDrive/GANstudy/PGGAN/checkimgs/shift5-img-{s}~{s+30}-mavg.jpg', dst) for i in range(0,5000,30): visualizeInterpolation(i) このコードはただ単純にseed値0〜29番の時の画像、30〜59番の時の画像...を出していくだけのものです。 このコードを実行するとこんな感じの画像が出ます。 そして何も言わず次のコード #checkimgs/shift-img-{seed}.jpgとして保存 #画像を混ぜてみる import random device = 'cuda' if torch.cuda.is_available() else 'cpu' #画像シフトしていくシード値を二つ指定 #3つくらいまでなら混ぜても大丈夫、4つからは怪しい #3つくらい混ぜると目がおかしくなりやすい mixseeds = [2726,724] mixnum = 2 mix = random.sample(mixseeds, mixnum) filename = "image5" netG_mavg = Generator().to(device) # moving average netG_mavg.load_state_dict(torch.load('/content/drive/MyDrive/GANstudy/PGGAN/models4/5-last-netG_mavg.pth')) optG = torch.optim.Adam(netG_mavg.parameters(), lr=0.001, betas=(0.0, 0.99)) def visualizeInterpolation(mix): np.random.seed(seed=mix[0]) z = np.random.randn(1,512*16) for seed in mix[1:]: np.random.seed(seed=seed) z2 = np.random.randn(1,512*16) z = np.concatenate([z,z2],axis = 0) z = np.clip(z,-1.,1.) z[0] = z[0]*0.5 z[1] = z[1]*0.5 vectors = [z[0]] #値をすこしずつshift for mininoise in z[1:]: vectors[0] = vectors[0]+mininoise print(vectors) vectors = np.array(vectors) vectors = torch.from_numpy(vectors.astype(np.float32)).to(device) netG_mavg.eval() dst = netG_mavg.forward(vectors, 6) dst = F.interpolate(dst, (256, 256), mode='nearest') dst = dst.to('cpu').detach().numpy() n, c, h, w = dst.shape dst = dst.reshape(c,h,w) dst = dst.transpose(1,2,0) dst = np.clip(dst*255., 0, 255).astype(np.uint8) dst = cv2.cvtColor(dst, cv2.COLOR_BGR2RGB) cv2.imwrite(f'/content/drive/MyDrive/GANstudy/PGGAN/checkimgs/mix-{filename}-mavg.jpg', dst) visualizeInterpolation(mix) (ちょっとコードおかしいかもしれない) このコードは、seed値①のベクトルをseed値②のベクトルに少しずつ近づけていき、それに応じた画像を出すだけのコードです。 このコードを実行するとこんな感じの画像が出ます。 これができると、seed値100個くらい保存しておくだけで、精度が保証されている画像を1〜10万枚以上(正確な数字はわからない)生成できるようになります。単純に決め打ちした画像を生成するときにも使えるので、ベクトルどうこうの話は覚えておきましょう。ちなみにベクトルの特性をフル活用したGANの種類にcGANがあります。まだ実装してませんがそこまで難しくないので、そのうちやります。 最後に 長くなってしまい申し訳ありません。また、力不足でPGGANの解説をしっかりとする自信がなかったので、今回の記事ではソースコードのみとなっています。 力を付けたらまた別の記事で書こうと思います。 それではまたどこかで。ついったーふぉろーLGTMよろしくね〜
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

初めての機械学習① 回帰とは

はじめに 現在、妻と共に年子の子供2人の子育てしながら普通のサラリーマンからエンジニアを目指し毎日最低2時間は機械学習を学習中の福本貴大(フクモトタカヒロ)です! Ruby on Railsで2つのアプリケーションを作っていてバックエンド作業が好きな事に気づき、データ分析エンジニアになろうと決めました! 今回は、pythonを使って私がデータ分析に必要な機械学習の基礎について、習った事をどんどんアウトプットしていこうと思います。 機械学習を使ったデータ分析の大まかな流れ 1.課題の設定(知りたいデータ(目的)の設定) 2.データの準備(目的に対し、どんなデータが必要か) 3.データの前処理(目的に対しデータの相関関係や欠損が無いか、いらないデータの削除など) 4.モデルの作成(下記参照) 5.モデルの評価(テスト用のデータでモデルがちゃんと機能してるのか確認) モデルとは 回帰や分類など、目的に適したアルゴリズを使って与えられたデータを元に予測するモノ。 回帰とは 周辺の物価情報などから土地の値段や売上予測など、データを元に計算し予測する手法のこと。 ※注意)サイコロの目を当てる様な確率を当てる様な予測ではない 線形回帰モデルとは 線形回帰(Linear Regression)は、特徴量(人であれば身長や体重など)と重み(身長であれば170㎝などの数値)を線形の多項式で表したもの。 特徴量と重み=説明変数 調べたいデータ=目的変数 y(目的変数)= ax(aが重み、xが特徴量の目的変数)+b(誤差) 上記の式の式を単回帰分析といい、説明変数が複数ある場合の式を重回帰分析という。 終わりに 私は文系で数学が苦手だったので今回は集中力が切れ少しだけになりますが、おそらくこれから機械学習を学ぶうえで絶対必要な事だと思うのでブログを書き共有させて頂きました! お役に立てば光栄です。 ではまた!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python】YouTube APIを使った「再生順、更新順(再生数下限あり)」動画リスト取得(コピペでOK)

はじめに YouTube Data APIを使って色々とお遊び開発をしようと思っています。 とりあえず今回はAPIを使う初級編として「再生順・更新順」の動画リストを取得します。 新人プログラマ応援期間ということで、コピペで使えるようにコードをそのまま載せようと思います。 ※YouTube Data API の使用にはAPIキーが必要です。 上記の記事で取得の説明をしています。 準備 少しだけ準備が必要です。 必要なPythonモジュールをインストールします。 pip install google-api-python-client pip install apiclient キーワードで検索(デフォルト) まずは簡単に余計な条件を入れずにキーワードで検索してみます。 以下の条件で情報を取得 キーワード「YOASOBI」 取得対象は「タイトル」、「動画URL」 取得件数は10件 コード from apiclient.discovery import build API_KEY = "<APIキーを入力>" KEY_WORD = "YOASOBI" MAX_RESULT = 10 def youtube_search(): youtube = build("youtube", "v3", developerKey=API_KEY) search_response = youtube.search().list( q=KEY_WORD, part="id,snippet", maxResults=MAX_RESULT ).execute() videos = [] for search_result in search_response.get("items", []): if search_result["id"]["kind"] == "youtube#video": videos.append("%s (https://www.youtube.com/watch?v=%s)" % (search_result["snippet"]["title"], search_result["id"]["videoId"])) print("\n".join(videos)) if __name__ == "__main__": youtube_search() 出力 タイトル(URL)を出力しています。 YOASOBI「夜に駆ける」 Official Music Video (https://www.youtube.com/watch?v=x8VYWazR5mE) YOASOBI「三原色」ahamo Special Movie (https://www.youtube.com/watch?v=ZNFKZI7L9xE) YOASOBI - 群青 / THE FIRST TAKE (https://www.youtube.com/watch?v=NyUTYwZe_l4) YOASOBI - 優しい彗星 / THE FIRST TAKE (https://www.youtube.com/watch?v=EaA6NlH80wg) YOASOBI「怪物」Official Music Video (YOASOBI - Monster) (https://www.youtube.com/watch?v=dy90tA3TT1c) YOASOBIのベストソング - YOASOBIメドレー - YOASOBIのベストカバー - Best Songs Of YOASOBI,夜に駆ける ,ハルジオン,あの夢をなぞって,ハッピーエンダ (https://www.youtube.com/watch?v=NXsAQtcfOyY) YOASOBI - 夜に駆ける / THE HOME TAKE (https://www.youtube.com/watch?v=j1hft9Wjq9U) YOASOBI「優しい彗星」Official Music Video (YOASOBI - Comet) (https://www.youtube.com/watch?v=VyvhvlYvRnc) 夜に駆ける / YOASOBI (cover) by Kradness (https://www.youtube.com/watch?v=UuboPsQ7gfA) YOASOBI「アンコール」Official Music Video (https://www.youtube.com/watch?v=vcGbefQBvJ4) 取得出来ました。簡単ですね。 コードの解説(一部) 少しコードの解説もしようと思います。 まず関数「youtube_search()」内の下記行でyoutubeに問い合わせる準備をしています。 (APIクライアントの作成) youtube = build("youtube", "v3", developerKey=API_KEY) 次に下記のコードにて、YouTube APIのsearch APIのlist()関数を使って動画情報を取得しています。 search_response = youtube.search().list( q=KEY_WORD, part="id,snippet", maxResults=MAX_RESULT ).execute() 最後に以下のコードにて取得結果から必要な情報を抽出しています。 for search_result in search_response.get("items", []): if search_result["id"]["kind"] == "youtube#video": videos.append("%s (https://www.youtube.com/watch?v=%s)" % (search_result["snippet"]["title"], search_result["id"]["videoId"])) APIの取得結果(JSON)は以下の形式です。 { "kind": "youtube#searchResult", "etag": etag, "id": { "kind": string, "videoId": string, "channelId": string, "playlistId": string }, "snippet": { "publishedAt": datetime, "channelId": string, "title": string, "description": string, "thumbnails": { (key): { "url": string, "width": unsigned integer, "height": unsigned integer } }, "channelTitle": string } } キーワードで検索(再生順) 次に再生順で取得したいと思います。 以下の条件で情報を取得 キーワード「YOASOBI」 取得対象は「再生数」、「タイトル」、「動画URL」 取得件数は10件 再生順で出力 コード 再生順にするにはクエリのオプションorder="viewCount"を指定するだけです。 せっかくなので再生回数も出力したいと思います。 再生回数はAPIの別メソッド「Videos:list」を使用しないと取得出来ないため、少しだけコードが長くなります。 from apiclient.discovery import build API_KEY = "<APIキーを入力>" KEY_WORD = "YOASOBI" MAX_RESULT = 10 ORDER = "viewCount" youtube = build("youtube", "v3", developerKey=API_KEY) def get_view_count(id): view_count = youtube.videos().list(part = 'statistics', id = id).execute()['items'][0]['statistics']['viewCount'] return view_count def youtube_search(): search_response = youtube.search().list( q=KEY_WORD, part="id,snippet", maxResults=MAX_RESULT, order=ORDER ).execute() videos = [] for search_result in search_response.get("items", []): if search_result["id"]["kind"] == "youtube#video": view_count = get_view_count(search_result["id"]["videoId"]) videos.append("[%s]%s (https://www.youtube.com/watch?v=%s)" % (view_count.rjust(10), search_result["snippet"]["title"], search_result["id"]["videoId"])) print("\n".join(videos)) if __name__ == "__main__": youtube_search() 出力 [再生数]タイトル(URL)を出力しています。 ※再生数は左空白埋め [ 201551492]YOASOBI「夜に駆ける」 Official Music Video (https://www.youtube.com/watch?v=x8VYWazR5mE) [ 97120569]YOASOBI - 夜に駆ける / THE HOME TAKE (https://www.youtube.com/watch?v=j1hft9Wjq9U) [ 56332898]YOASOBI「怪物」Official Music Video (YOASOBI - Monster) (https://www.youtube.com/watch?v=dy90tA3TT1c) [ 46933545]YOASOBI「ハルジオン」Official Music Video (https://www.youtube.com/watch?v=kzdJkT4kp-A) [ 29086025]YOASOBI「群青」Official Music Video (https://www.youtube.com/watch?v=Y4nEEZwckuU) [ 27845585]YOASOBI「たぶん」Official Music Video (https://www.youtube.com/watch?v=8iuLXODzL04) [ 26438752]YOASOBI「あの夢をなぞって」 Official Music Video (https://www.youtube.com/watch?v=sAuEeM_6zpk) [ 23614258]YOASOBI - 群青 / THE FIRST TAKE (https://www.youtube.com/watch?v=NyUTYwZe_l4) [ 20267654]YOASOBI「アンコール」Official Music Video (https://www.youtube.com/watch?v=vcGbefQBvJ4) [ 16635646]怪物 (https://www.youtube.com/watch?v=hYF438PiuPI) 表示順指定 ここで表示順の指定が出てきたので他の表示順指定も載せておきます。 date – リソースを作成日の新しい順に並べます。 rating – リソースを評価の高い順に並べます。 relevance – リソースを検索クエリの関連性が高い順に並べます。このパラメータのデフォルト値です。 title – リソースをタイトルのアルファベット順に並べます。 videoCount – アップロード動画の番号順(降順)にチャンネルを並べます。 viewCount – リソースを再生回数の多い順に並べます。 YouTube Data API公式ドキュメント キーワードで検索(更新順) 次に更新順(最新のもの順)で取得したいと思います。 以下の条件で情報を取得 キーワード「YOASOBI」 取得対象は「作成日時」、「再生数」、「タイトル」、「動画URL」 取得件数は10件 更新順(降順)で出力 コード from apiclient.discovery import build API_KEY = "<APIキーを入力>" KEY_WORD = "YOASOBI" MAX_RESULT = 10 ORDER = "date" youtube = build("youtube", "v3", developerKey=API_KEY) def get_view_count(id): view_count = youtube.videos().list(part = 'statistics', id = id).execute()['items'][0]['statistics']['viewCount'] return view_count def youtube_search(): search_response = youtube.search().list( q=KEY_WORD, part="id,snippet", maxResults=MAX_RESULT, order=ORDER ).execute() videos = [] for search_result in search_response.get("items", []): if search_result["id"]["kind"] == "youtube#video": view_count = get_view_count(search_result["id"]["videoId"]) videos.append("[%s][%s]%s (https://www.youtube.com/watch?v=%s)" % (search_result["snippet"]["publishedAt"], view_count.rjust(6), search_result["snippet"]["title"], search_result["id"]["videoId"])) print("\n".join(videos)) if __name__ == "__main__": youtube_search() 出力 [作成日時][再生数]タイトル(URL)を出力しています。 ※再生数は左空白埋め [2021-04-12T14:52:02Z][ 1]群青(YOASOBI) covered by MOMOKA 2021.4.7 at CIB (https://www.youtube.com/watch?v=7HsmvKr74UI) [2021-04-12T14:30:21Z][ 19]【ハルジオン/YOASOBI】グレード5級 エレクトーン 弾いてみた (https://www.youtube.com/watch?v=wE_yQb60r08) [2021-04-12T14:25:27Z][ 4][THAISUB] YOASOBI - Tabun (たぶん) (https://www.youtube.com/watch?v=cK9w64QPKK0) [2021-04-12T14:11:47Z][ 4]YOASOBI/あの夢をなぞって 弾き語り 16歳 (https://www.youtube.com/watch?v=JvFZsT9olFI) [2021-04-12T14:10:37Z][ 2]夜に駆ける(YOASOBI) covered by MOMOKA 2021.4.7 at CIB (https://www.youtube.com/watch?v=7WVpfXbbt-I) [2021-04-12T14:00:11Z][ 89]Yasashii Suisei / 優しい彗星 by YOASOBI | BEASTARS Season 2 ED | Kalimba Tutorial &amp; Tab (Hard) (https://www.youtube.com/watch?v=cApb2qTcBEo) [2021-04-12T14:00:14Z][ 13]【作業用BGM】ヨルシカ×YOASOBI×ずとまよ代表曲メドレー【オルゴール】 (https://www.youtube.com/watch?v=rtqZsLNVTz 8) [2021-04-12T13:45:27Z][ 24]【YOASOBI 群青】アジアランカーによる最強キル集【フォートナイト/Fortnite】 (https://www.youtube.com/watch?v=1iKZPZN4prs) [2021-04-12T13:00:13Z][ 812]#341 The First Take 史上最多人同時錄音YOASOBI【群青】 ◆嘎老師 Miss Ga|歌唱教學 學唱歌◆ (https://www.youtube.c om/watch?v=ZVYyBugDa6o) [2021-04-12T13:00:17Z][ 118]【豊洲lovepiano5号機】通行人が立ち止まる!?YOASOBI『群青』を超絶技巧アレンジで弾いてみた!!!-YOASOBI“Gunjou ” by mina (https://www.youtube.com/watch?v=pKaXWJ_MjNk) 作成日時は ISO 8601(YYYY-MM-DDThh: mm:ss.sZ)形式です。今回は問題ないので変換しません。 キーワードで検索(更新順・再生数下限設定) 更新順で取得したのは良いのですが、あんまりおもしろそうではない動画が出てきます。 (一生懸命動画作成していらっしゃる方に本当に申し訳ないですが) そこで再生数の下限を設定したいと思います。 しかしYouTube Data APIの公式ドキュメントを見ると再生数での絞り込みが出来ないとのこと。 なので取得上限まで情報を取得して、Pythonコードで絞り込むことにしました。 以下の条件で情報を取得 キーワード「YOASOBI」 取得対象は「作成日時」、「再生数」、「タイトル」、「URL」 取得件数はMAX(上限は50件) 更新順(降順)で出力 再生数1,000回以上が対象 コード from apiclient.discovery import build API_KEY = "<APIキーを入力>" KEY_WORD = "YOASOBI" MAX_RESULT = 50 UNDER_VIEW_COUNT = 1000 ORDER = "date" youtube = build("youtube", "v3", developerKey=API_KEY) def get_view_count(id): view_count = youtube.videos().list(part = 'statistics', id = id).execute()['items'][0]['statistics']['viewCount'] return view_count def youtube_search(): search_response = youtube.search().list( q=KEY_WORD, part="id,snippet", maxResults=MAX_RESULT, order=ORDER ).execute() videos = [] for search_result in search_response.get("items", []): if search_result["id"]["kind"] == "youtube#video": view_count = get_view_count(search_result["id"]["videoId"]) if int(view_count) >= UNDER_VIEW_COUNT : videos.append("[%s][%s]%s (https://www.youtube.com/watch?v=%s)" % (search_result["snippet"]["publishedAt"], view_count.rjust(6), search_result["snippet"]["title"], search_result["id"]["videoId"])) print("\n".join(videos)) if __name__ == "__main__": youtube_search() 出力 [作成日時][再生数]タイトル(URL)を出力しています。 ※再生数は左空白埋め [2021-04-12T11:00:30Z][ 2121]【意外】YOASOBIの二人の最近の悩み (https://www.youtube.com/watch?v=d76QETcfBqY) [2021-04-12T09:00:21Z][ 1100]岡山駅前YOASOBIエリア【夜街探訪】岡山駅の玄関口&amp;外国人に聞いてみる (https://www.youtube.com/watch?v=UQePX0C5tXg) [2021-04-12T09:00:00Z][ 14312]【やばすぎwwww】下ネタを真面目に話すYOASOBIの二人wwww (https://www.youtube.com/watch?v=2BwxFMzjKBs) [2021-04-12T08:30:05Z][ 1566]JPOP ランキング 邦楽 2021 ♫ Youtube Charts #01 ♫ LiSA, Hikaru Utada, Yuuri, YOASOBI, Official髭男dism, Aimyon (https://www.youtube.com/watch?v=wAUgNQLRvYk) [2021-04-11T13:49:33Z][ 3779]빨강, 파랑, 초록의 이야기?: YOASOBI - 삼원색(三原色) [가사/발음/한글 자막] (https://www.youtube.com/watch?v=xWN0wCmXfto) [2021-04-11T11:00:01Z][811486]【踊ってみた】三原色 / YOASOBI (オリジナル振付) (https://www.youtube.com/watch?v=QBK9rSYGRCE) 良い感じになりました。 他にもオプションを変えて色々いじってみようと思っています。 まずは以下のライブラリと組み合わせて自動ダウンロードバッチを作成予定です。 以上です。 公式ドキュメント
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

BigSleepで憧れだった画家になろう![GAN]

はじめに こちらの記事はBigSleepを使用して文章から絵をつくる(Text to Art)実践方法をさくっとまとめたものになります。まだまだ記事が少なそうだったのでGoogle ColaboratoryによるBigSleepの使い方を中心に紹介しています。 かくいう私自身、つい先日GHELIA清水亮CEOの講演にてBigSleepの存在を知り、試してみたクチです。これから勉強していきたいと思っています。 「老後は油絵でも描いて暮らしたいな」「漫画家になりたかった」..そんな人には大変朗報です。(僕です。)一緒に芸術を爆発させましょう! BigSleepとは GitHub : https://github.com/lucidrains/big-sleep.git READMEを攻めの要約すると「GANを使って、自然言語から絵を夢見ることができる」そうです。オシャレだなぁ〜。 version 0.0.1が今年の1月19日ということで結構ホカホカなライブラリです。 百聞は一見に如かず、ということで GitHubのsampleでも書かれている"fire in the sky"をBigSleepに流し込んでしばらくすると以下のような画像が得られました。 1952: 伊藤佳十郎 「追憶の朱空」 とか書かれたら信じてしまいそうです。(もちろん全部でたらめです) Google Colaboratoryで試してみる ここからが本記事の本題です。 GPU必須なので、GPUお持ちでない方はGoogle Colaboratoryを使用しましょう。 ランタイムのタイプをGPUに変更してください。 CodeはREADMEのsample文章そのままです。はじめて実行する場合は!pip installしてあげてください。textの中身をあなたの思うまま書いてみましょう。日本語でも生成画像の内容はともかく動作はするみたいです。 !pip install big_sleep from big_sleep import Imagine dream = Imagine( text = "I like coffee", lr = 5e-2, save_every = 25, save_progress = True ) dream() 上記を実行すると、Imagingが開始され、epoc毎の絵が保存されていきます。 Colaboratory左側にあるFolderマークをクリックすると、生成された画像データが確認できます。(自身が不慣れなもので、ここで少し躓きました..) この記事を書きながら30分ほど放置してできた作品がこちらです。右側には私の解釈を付け加えています。笑 なんとなくI like coffeeを表していそうな感じもしますし、少なくとも私の頭の中からは現れてこないArtです。AIが描いた絵から逆にインスピレーションを受ける、っていう事を体感しますね。 結論:なにこれ面白い BigSleepにも感謝ですし、GPU使わせてくれるGoogle Colaboratoryにも感謝です。 AIと芸術のコラボレーションは今後も注目していきたいですね! ひらめいた文章をArtにして、noteとかインスタとかに投稿してみようと思います。(オサレ)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

BigSleepで憧れだった画家になろう!

はじめに こちらの記事はBigSleepを使用して文章から絵をつくる(Text to Art)実践方法をさくっとまとめたものになります。まだまだ記事が少なそうだったのでGoogle ColaboratoryによるBigSleepの使い方を中心に紹介しています。 かくいう私自身、つい先日GHELIA清水亮CEOの講演にてBigSleepの存在を知り、試してみたクチです。これから勉強していきたいと思っています。 「老後は油絵でも描いて暮らしたいな」「漫画家になりたかった」..そんな人には大変朗報です。(僕です。)一緒に芸術を爆発させましょう! BigSleepとは GitHub : https://github.com/lucidrains/big-sleep.git READMEを攻めの要約すると「GANを使って、自然言語から絵を夢見ることができる」そうです。オシャレだなぁ〜。 version 0.0.1が今年の1月19日ということで結構ホカホカなライブラリです。 百聞は一見に如かず、ということで GitHubのsampleでも書かれている"fire in the sky"をBigSleepに流し込んでしばらくすると以下のような画像が得られました。 1952: 伊藤佳十郎 「追憶の朱空」 とか書かれたら信じてしまいそうです。(もちろん全部でたらめです) Google Colaboratoryで試してみる ここからが本記事の本題です。 GPU必須なので、GPUお持ちでない方はGoogle Colaboratoryを使用しましょう。 ランタイムのタイプをGPUに変更してください。 CodeはREADMEのsample文章そのままです。はじめて実行する場合は!pip installしてあげてください。textの中身をあなたの思うまま書いてみましょう。日本語でも生成画像の内容はともかく動作はするみたいです。 !pip install big_sleep from big_sleep import Imagine dream = Imagine( text = "I like coffee", lr = 5e-2, save_every = 25, save_progress = True ) dream() 上記を実行すると、Imagingが開始され、epoc毎の絵が保存されていきます。 Colaboratory左側にあるFolderマークをクリックすると、生成された画像データが確認できます。(自身が不慣れなもので、ここで少し躓きました..) この記事を書きながら30分ほど放置してできた作品がこちらです。右側には私の解釈を付け加えています。笑 なんとなくI like coffeeを表していそうな感じもしますし、少なくとも私の頭の中からは現れてこないArtです。AIが描いた絵から逆にインスピレーションを受ける、っていう事を体感しますね。 結論:なにこれ面白い BigSleepにも感謝ですし、GPU使わせてくれるGoogle Colaboratoryにも感謝です。 AIと芸術のコラボレーションは今後も注目していきたいですね! ひらめいた文章をArtにして、noteとかインスタとかに投稿してみようと思います。(オサレ)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む