空飛ぶ気まぐれ雑記帳

主に趣味とかプログラミングについて扱います。

PythonでGUIアプリケーションを作ろうとした話

はじめに

今回の話はタイトルどおり、Pythonを使ってGUIアプリケーションを作ろうとした話です。
これまでに、C++でアプリケーションを作ったことは数多くあれど、他の言語でアプリケーションを作った経験は少ないものです。
特に、スクリプト言語に絞ると無いと言っても過言ではないでしょう。

というのも、スクリプト言語というと、研究で何かしらの実験をして、その実験結果を整理するためのもの。
というイメージが強く、どうしても書捨てなイメージが強かったからです。

その一方で、C++でアプリケーションを作ると常に膨大な行数のソースコードとファイル数で、1つ作り上げるのに結構な時間を要するという至極一般的な問題がありました。
その上、実装中に「この書き方はできるだろ」と思ってたら実は駄目ですということがママあり*1、急遽設計を変更する羽目に会うことがあります。

そのため、あまりC++でアプリケーションを書ききったことがないという現実があります*2

いくらなんでもそれは…と思い至り、少しでも完成率を上げるために、それならスクリプト言語で書けば良いんじゃねと結論に至りました。

そんなわけで、今回紹介するのはPythonGUIアプリケーションを作る過程の話を紹介したいと思います。

GUIライブラリの選定

tkinter

言わずと知れた、Python付属のGUIライブラリ。
比較的簡単に使えるらしいのですが、どうも完成しても見た目があまり良くないそうで、ユーザー数が少ないそうです。
実際Googleで検索してもあまり込み入った話を書いたブログが見つからなかったので、実際少ないのでしょう。
というわけで、今回はボツ案で。

wxPython

wxWidgetsPythonバインディング
C++版に比べて使いやすいらしいのですが、wxWidgetsWindows版はとにかくバグが多い*3上に、かなりお作法に厳しいので、あまり好きではありません。
というわけでボツですね。

PyQt5

Qt5のPythonバインディング
文字列を標準のstring型ではなく、QString型をバインディングしたクラスを使ったりと結構面白いバインディングの仕方をしているライブラリです。
イベントの扱いにC++版と若干違いがあって、connectでSIGNALとSLOTというマクロを使って接続していたのですが、signal型のconnectを使ってslotを直接接続する感じになっています。
書いていてよくわからないので、例をあげます。実際にボタンのクリックイベントを使う時は下記のようにします。

button.clicked.connect(self.onClicked)

ただ、このライブラリ。
色々あって、ライセンスがLGPLではなく、GPLでしかライセンスされていません。
そのため、開発したアプリケーションにもGPLでライセンスをする必要があるため、注意が必要です。

そのため、今回はできればGPLでライセンスしたく無かったのでボツにしました。

PySide

PyQt5の作者が作ったLGPLでライセンス可能なQt5のPythonバインディング
PyQt5との違いは文字列型にPython標準のstringを使っているなどなど。
詳しくはググってください。

基本的にはC++版とのQtと使い方に違いは無いので、慣れていることもあって、今回はPySideにしました。

アプリケーションのデプロイ

Pythonで作ったアプリケーションのデプロイについてです。
通常Pythonスクリプト言語ですので、実行にインタプリタを必要とします。
しかし、それだと、自分が作ったアプリケーションをプログラマでないユーザに使ってもらおうとすると、ユーザにもPythonインタプリタをインストールすることを強いる必要があります。
それを回避するためのデプロイ用のアプリケーションを選定します。

今回作成したアプリケーションはPython3系で書いたので、Python3系で問題なく動作するアプリケーションが必要です。

下記で紹介しているアプリケーション全てpipからインストール可能なのでインストールも楽に済みます。

py2exe

多分一番有名なデプロイアプリケーション。
py2appなど、Windwos環境以外に向けた実装も用意されているため一応マルチプラットフォームで活用することが出来ます。
しかし、私の環境(Python3.5.2)ではどうもうまく動作せず。
実行中にエラーメッセージを吐いて異常終了してしまったので、うまくデプロイすることが出来ませんでした。

PyInstaller

py2exeでは、アプリケーションのデプロイに設定ファイルとしてのPythonスクリプトが必要なのですが、こいつはそれを必要としません。
ソースコードを解析して、必要なDLLを決定しているそうなのですが、その解析があまり賢くないため、過剰にDLLを集めてしまうそうです。
ただ、こいつの場合、entryポイントエラー(だったかな)DLL不足ではない謎の例外を吐いて、私の環境では上手く動いてくれなかったので、諦めました。

cx_Freeze

前2つと何が違うかと言われると「なんだろう?」ってなるくらいに、よく調べていません。
それはさておき、こいつは、py2exeと同様、設定ファイルを必要とするタイプですが、結構安定して動作するそうです。
それで実際に試してみると、一部DLLが不足してEXE起動時にDLL無いよって例外吐いて落ちてしまいました。
なんだか、進歩があったようなので、もう少し調べてみると、そういう場合はpackagesに含まれなかったライブラリを手動で足せば良いそうです。

実際に書いたsetup用のスクリプトは下記の通りです。
いまいちpackagesとincludesの違いはわかりませんが…とりあえず、こう書くそうです。

import sys
from cx_Freeze import setup, Executable

base = None
if sys.platform == 'win32':
	base = 'Win32GUI'

packages = ['lxml']      # これがデプロイされなかったライブラリ
includes = ['PySide']    # デプロイ時に含めて欲しいライブラリ 
excludes = ['PyQt4']     # デプロイ時に含めて欲しくないライブラリ

setup(  
	name = 'Scripter',  # アプリケーション名
	version = '0.1',    # アプリケーションのバージョン
	description = '',
	options = { 'build_exe' : {'includes':includes, 'excludes':excludes, 'packages': packages} },
	executables = [Executable('main.py', base=base, icon='ICON.ico', targetName='Scripter.exe')] 
	#出力するアプリケーション名やアイコンファイルを設定
)

インストーラの作成

インストーラの作成というとアプリケーションを本格的にユーザにデプロイする場合にしか必要としないため、あまり需要がない or そういうことをする人は自分で調べられるからなのかはわかりませんが、このあたりは日本語資料があまりないので、とりあえず書いておこうと思いました。

Install Shield

いわずと知れた、インストーラの代名詞的存在。いろんなソフトで見かけるかと思います。
しかし、こいつ、ライセンス条項が結構怪しいらしく、使用するPCをInstallShieldの開発元に監視されるらしく結構やばい。
というわけで、今回は候補から外します。

WiX

Microsoftが現在オープンソースで開発しているアプリケーションで、XMLベースのマークアップを記述することでインストーラを作成することができます。
ただ、その仕様とXMLの言語仕様が相まって書くのが非常にめんどくさい。
その上、資料と言える資料が英語Wikiのみで学習コストも高いですし、そもそもファイル数が増えると書くのがめんどくさい。

NSIS

NSIS Wiki
というわけで、今回の本命。
こいつはWiXと同じくスクリプト形式のインストーラ作成アプリケーションなのですが、文法がスペース区切りのbashの設定ファイルのような形式になっていて、WiXとくらべて書きやすい文法になっています。
また、こいつの優れている点としてzipファイルからインストーラを自動生成できる点があります。
その設定も非常に簡単で、zipファイルを選択して、あとはOKボタンを押すだけでできます。

おわりに

今回はPythonアプリケーションをデプロイしてインストーラを作成するところまで紹介しました。特にインストーラを作る部分は初めてやってみましたが非常に簡単でした。
が、作ったアプリケーションをいかに公開するかという難題がまだ残っています。
それについては少々悩んでいるので、また今度。

*1:え、文法を覚えて無いのかって?いいえ、そういう訳ではなく。Qtお前のことだよ。

*2:だいたい10個に3個ぐらいの割合でしか完成までたどり着きません

*3:OpenGLのコンテキストが解法されずメモリリークするとか、Sliderオブジェクトの再描画がされないとか

CNTKがガチでクソだったと思ってたらいつの間にかそうでも無くなってた話

はじめに

前回の記事を書いている最中に思い出したのだけれども、CNTKがガチでクソだった話を書こうと思ったらいつの間にかそうでも無くなってた話。

近況と生存報告と人気ページについて - 空飛ぶ気まぐれ雑記帳

そもそもCNTKって

CNTKとはMicrosoft社が提供しているオープンソースディープラーニングのライブラリで、マルチGPU性能が非常に高いことと、複数台のPCで実行可能なことを売りにしているディープラーニングライブラリです。
どれくらいマルチGPU性能が高いかと言うと、そもそもマルチGPUに対応していないTheanoは置いておいて、Tensor FlowやTorch、Caffeの倍近い性能を持つ他、2台のPCに各4基、合計8基のGPUを搭載して計算すると、他のライブラリよりも圧倒的に早いZEってライブラリです。
さらに、Microsoftが出しているだけあって、Windows対応を謳っている数少ないディープラーニングのライブラリでもあります。

github.com

CNTKのどこが糞だったん

これはあくまでもメジャーリリース当時の話です

私も上の説明を見た時はなんて素敵なライブラリなんだと、目を輝かせたものです。
ただ、それも幻影でした。

最初、Readmeとかよく読まず、とりあえず"cmake --build . --target Debug"とかでVisual Studioを起動せずに適当にビルドしようとしてたのですが、どうも成功せず。
とりあえず、slnファイルを開いてVisual Studioからビルドすかと思った矢先。なんとプロジェクト名に括弧書きで「Only Visual Studio 2013」(だったかな)と書かれていたのです。
それで、詳しく調べてみると、なんとこのCNTK、Visual Studio 2013にしか対応していないガチクソだったのです。

だったのですが…

今日、この記事を書こうとgithubを見てみると、最新のバージョンだとVisual Studio 2015に対応しているそうです。

github.com

という訳で一転して、CNTKは神ライブラリかもしれません。
また、暇になったら記事を書くかもしれませんが、、、いつに成ることやら

近況と生存報告と人気ページについて

先月からクソ忙しくて、録に更新してこなかったけどいい加減更新しようと思いいたった。のだけれども、どうも記事にできる内容がない。
いや、この三ヶ月、何もしてこなかった訳ではない。一応、研究成果の方はしっかり出して、それ相応の評価を頂戴した。
ただ、このブログに書けるような内容が、どれも進捗半端で紹介しかねるという状況だった。例えば、Webアプリ作った話とか、tensor flowのWindows版をインストールして使ってみた話とかCNTKがクソだった話とか、DLIBでDCGANを実装しようとして死にそうになってる話とか、もう色々あるんだけど……。
それで、とりあえず。はてブの編集ページへ飛ぼうとはてブのトップを開くと、右上のアカウント名のところに赤い通知が来ていた。

PV数が100を超えました

これを見た瞬間「はぁ?」となり、さらにPV数を確認して「……」となった。なんと、月間PVが100と言わず404になっていた。これまで、と言っても最後に更新したのは12月の話だが、その時は月間PV数なんて50を超えれば良いほうだった。それがほったらかしにした2ヶ月の間に何があったのかという話だ。

それで、記事の人気順を出して見るとその原因が何となく分かった。

総アクセス数に占める割合 ページ名
23% C++でDNNが使えないなんてあるわけないよ in Windows
20% CUDA 8.0がいつの間にかリリースされててVisual Studio 2015 Update 3でも使えるようになっていた話
11% DLIBでCNNを使ってみた in Windows
11% DLIBのコンパイル For Debugビルド
6% DLIB with CUDAでCNNを使ってみた in Windows
4% Windowsffmpegを使ってみた話
3% /category/機械学習
2% /category/dlib
2% GLEWをVisual Studio 2015とCMakeでビルドするときの注意点
2% ブログトップ
2% OpenGLでズームを実装する方法
1% GPGPUって色々あるけど結局どれがいいの
1% SFINAEやテンプレートの部分特殊化で気をつけたいこと
1% Visual Studio で拡張子のないC++ヘッダーをIntelli Senseで表示する方法
0% PythonでDLLを使う時の話
0% /category/深層学習
0% Visual Studioユーザーに送るCMakeテクニック☆ (1)
0% cygwinでFindOpenCVするとエラーになる
0% Visual Studioユーザーに送るCMakeテクニック☆ (2)


あー、ただのディープラーニングか。実際、「C++ DNN」とか「DLIB DNN」でGoogle検索を掛けると、ビックリするほど上位に出てくるから、やはりそういうことらしい。

とりあえず、今後もディープラーニングの話は書いていくつもりですのでよろしくお願いします。あ、それとCMake絡みの記事も読んでくれてもええんやで。

Visual Studioユーザーに送るCMakeテクニック☆ (3)

いやーこれでもう第三回ですよ。
なんとか自分で設定した週一更新のノルマを達成できそうですねー

それはさておき、今日は(1)と(2)の続きにあたるはなしで、(2)はCMakeListsを対象としたものでしたが、今回はそれ以外のヘッダーファイルやソースファイルを対象としたものです。
今回は少し長いので、gistに上げました。

gist.github.com

かなり前に書いたためちょいちょいとお恥ずかしい部分(ぶっちゃけ汎用で作ればいいのになぜか専用品になってるあたりマジで…)もありますが、普通に使えるはずです。
下記は実際にこれを使い方です。実行したCMakeListsの保存されているディレクトリをルートとしてそのファイル内の全てのファイルについてフィルタリング&ファイルパスを取得できます。

使い方としては>|cmake|RecursiveGroupingWithFileSet(<探索するルートディレクトリ> <探索するディレクトリ一覧> <ヘッダーファイルの一覧が保存される変数名> <ソースファイルの一覧が保存される変数名>)|

なんかデスマってたからレムちーのボクセルキャラクターを描いてみた

学会前のセルフハンディキャッピングの一環としてなぜかボクセルキャラクターを作りたくなったのでRe:ゼロのレムを作ってみました。
参考は下記、3つのサイトです。

CHARACTER|TVアニメ『Re:ゼロから始める異世界生活』オフィシャルサイト
ultimei.hatenablog.com
github.dev7.jp

一番上は参考画像。まあRe:ゼロのアニメ版公式サイトですね。
それから、真ん中は基本的な書き方、一番下はテンプレートを拝借しました。

それで、実際に書いていて一箇所だけ詰まったのが、パレットの設定です。

パレットからいらない色を選択して、左下のHSVというペーン内で設定することができるのですが、
HSVというのはスライダーの部分のパラメータだけで、スライダーの下のテキストボックスはRGBなので、手打ちで色を入力する際は注意が必要です。

f:id:elda27:20161211005903p:plain

それ以外は特に詰まること無くスイスイと書くことができました。
もともと絵心がない上に製作時間が1時間なので出来具合はお察しください。

正面
f:id:elda27:20161211011721p:plain

頭上
f:id:elda27:20161211012821p:plain

側面
f:id:elda27:20161211012818p:plain

背面
f:id:elda27:20161211012824p:plain

パンツは未実装
f:id:elda27:20161211012815p:plain

ガラス調
f:id:elda27:20161211011728p:plain

メタル調
f:id:elda27:20161211011731p:plain

それでも、自分で作ったからか何となく愛着が湧いちゃって。もうね、どれ位かって言うとこんな記事を作っちゃうくらいですよね。

とりあえず、今後も作るかは分からないけれども、課題としてはもう少し凝ってみたいので、より大きなサイズのボクセルモデルを作ってみたいですね。

追記:
投稿してからすぐに気づいたのだけれども、なんかメイド服なのにしっくりこないなと思っていたら、カチューシャ(?)の存在を忘れていたので慌てて付け足しました。

f:id:elda27:20161211014917p:plain

Visual Studioユーザーに送るCMakeテクニック☆ (2)

Visual Studioユーザーに送るCMakeテクニック☆ 、第二回目です。
今回は、昨日の記事で説明したフィルタリング機能を使って、CMakeファイルをVisualStudioから簡単に見えるようにしようって話です。
具体的にはどういうことかと言うと下記のように各ディレクトリに配置されているCMakeListsと*.cmakeファイルをディレクトリ構造をフィルタ名としたCustomプロジェクトを作成します。

f:id:elda27:20161130000643p:plain

下記が実際のソースコードです。

FILE(GLOB_RECURSE CMAKE_LIST_FILES CMakeLists.txt *.cmake)

FOREACH(file ${CMAKE_LIST_FILES})
  FOREACH(dir ${CMAKE_CURRENT_LIST_DIR})
    FILE(RELATIVE_PATH relative ${CMAKE_CURRENT_LIST_DIR} ${file})
    
    STRING(REGEX MATCHALL "[^/]+" filters "${relative}")
    LIST(LENGTH filters output_length)
    MATH(EXPR iteration "${output_length} - 2")
    
    IF(${iteration} LESS 0)
      continue()
    ENDIF()
    
    SET(group_string "")
    FOREACH(i RANGE 0 ${iteration})
      LIST(GET filters ${i} g)    
      set(group_string "${group_string}\\${g}")
      #MESSAGE(${i},${output_length}:${g})
    ENDFOREACH()
    SOURCE_GROUP("${group_string}" FILES ${file})
  ENDFOREACH()
ENDFOREACH()

ADD_CUSTOM_TARGET(CMakeLists SOURCES ${CMAKE_LIST_FILES})
<||

Visual Studioユーザーに送るCMakeテクニック☆ (1)

はじめに

今月忙しすぎてブログの更新が滞っていたので、暫くごまかしのためにCMakeのテクニックを紹介します。
なお、未だに忙しくて録に記事が書ける状態ではないので記事は分割してますが、悪しからず。

決して当初掲げていた週一更新の分を一気に放出しようとしているわけではありません

それはさておき、今日紹介するのはVisual Studioが有するフィルタリング機能をCMakeから利用するにはどうすれば良いのか?
という話です。

フィルタリング機能って

Visual Studioでプロジェクトを右クリックしてでてくるポップアップメニューの Add > New Filterで出てくるアレです。
デフォルトでも、Source filesやHeader files(日本語版だとソースファイルとヘッダーファイルかな?)というものが設定されているかと思います。

このフィルタリング機能ですが、これがないとソースファイルの数が100近くなると非常に見づらくなるので、どっぷりとVisual Studioを使っている方は間違いなく利用しているかと思います。

これをCMakeを使ってソリューションファイルを生成するとデフォルトのSource filesやHeader filesのフィルタリングすらないため、非常に不便ですよね。

フィルタリングを有効にする

下記コマンドを実行すればフィルタリングが有効になります。
なお、デフォルトでSource filesとHeader filesが設定され、振り分けられます(久しくデフォルトの挙動を確認していないので不安ですが…)。

SET_PROPERTY(GLOBAL PROPERTY USE_FOLDERS ON) 

もし、これをONにしない場合、以下で説明している設定をしても反映されないので注意しましょう

ソースファイルをフィルタリングしたいとき

ソースファイルをフィルタに分類する場合、下記コマンドを実行すればOKです。

SOURCE_GROUP("任意のフィルタ名" FILES <ソースコードのファイルパス> ...)

なお、もしフィルタをネストする場合、例えば Source files > hoge > huga > hage.cpp のような階層構造を持たせたい場合、フィルタ文字列をバックスラッシュ2つ(文字列内の場合バックスラッシュをエスケープする必要がある?)並べる必要があります。

SOURCE_GROUP("Source files\\hoge\\huga" FILES hage.cpp)

のようになります。

プロジェクトをフィルタリングしたいとき

プロジェクトの場合ソースコードとは違う方法でフィルタリングを行います(フィルタリングのフォーマットは同じ)

SET_TARGET_PROPERTIES(<プロジェクト名(ターゲット名)> PROPERTIES FOLDER "任意のフィルタ名")

ここで注意しなければならないのが、ターゲットを対象としてフィルタリングするため、add_executable or add_library or add_custam_target etc... でターゲットを生成した後に呼び出す必要があるという所。

おわりに

ざっくりとCMakeを使ったフィルタリングの使い方を説明しました。
次回以降も個人的に知ってて便利だな―と思ったCMakeの使い方を説明していくつもりです。

なお、全五回くらいになる予定していますそんなにネタがあるか微妙ですが