- 投稿日:2020-10-20T23:36:12+09:00
no CUDA-capable device is detected
rayでGPUを使用し、並列処理をしていると以下のようなエラーがでる。
RuntimeError: cuda runtime error (100) : no CUDA-capable device is detected at /opt/conda/conda-bld/pytorch_1591914855613/work/aten/src/THC/THCGeneral.cpp:47エラーの対処方法
長らくこのエラーについて考えたが明確な答えは分からなかった。。。。
しかし、このエラーが出てもrayでGPUを使うことができる方法を見つけた。
それは実行したいプログラムに以下のコードを追加することである。
while True: input = input() #以下実行したいコード : :上記のコードを説明する。
まず、while Trueは無限ループである。
input()は入力である。
そして、while Trueの中に実行したいコードを入れる。タイトルのようなエラーが出たらcontrol Cで再び入力に戻す。
そしてまた、適当な入力をする。
するとエラーがなくなり実行できる。実行し終えたら
無限ループなので
control Cを押して終了する。本当の意味の解決方法を見つけたらまた報告する。
- 投稿日:2020-10-20T23:23:07+09:00
Chainerによる機械学習のためのPython学習メモ 11, 12章 Pandas Matplotlib 入門
What
Chainerを利用して機械学習を学ぶにあたり、私自身が、気がついた点、リサーチした内容をまとめる記事になります。今回は、scikit-learnを勉強します。
私の理解に基づいて記述しているため、間違っている場合があります。間違いは都度修正するつもりです、ご容赦ください。
Content
Pandas
Pandas はデータ操作によく用いられるパッケージであり、CSV などの一般的なデータ形式で保存されたデータの読み込みや、条件を指定しての一部データの抽出など、機械学習手法で取り扱うデータを整理するのに便利です。
とまぁ計算ツールみたいなものですね。算盤とか電卓とか計算を楽にしてくれる道具的な立ち位置です。ちなみに下記の操作ができるみたいです。
・CSV ファイルの読み書き
・統計量の算出
・並べ替え
・データの選択
・条件指定による選択
・欠損値の除去 / 補間
・ndarray とデータフレームを相互に変換
・グラフの描画Matplotlib
グラフを描けるライブラリ。折れ線、散布図、箱ひげなど。特筆すべき点は特に見当たらない。
またコード書きながら抑えるポイントが出てきたら追記します
- 投稿日:2020-10-20T23:23:07+09:00
Chainerによる機械学習のためのPython学習メモ 11章 Pandas 入門
What
Chainerを利用して機械学習を学ぶにあたり、私自身が、気がついた点、リサーチした内容をまとめる記事になります。今回は、scikit-learnを勉強します。
私の理解に基づいて記述しているため、間違っている場合があります。間違いは都度修正するつもりです、ご容赦ください。
Content
Pandas はデータ操作によく用いられるパッケージであり、CSV などの一般的なデータ形式で保存されたデータの読み込みや、条件を指定しての一部データの抽出など、機械学習手法で取り扱うデータを整理するのに便利です。
とまぁ計算ツールみたいなものですね。算盤とか電卓とか計算を楽にしてくれる道具的な立ち位置です。ちなみに下記の操作ができるみたいです。
・CSV ファイルの読み書き
・統計量の算出
・並べ替え
・データの選択
・条件指定による選択
・欠損値の除去 / 補間
・ndarray とデータフレームを相互に変換
・グラフの描画またコード書きながら抑えるポイントが出てきたら追記します
- 投稿日:2020-10-20T23:17:01+09:00
CNNと画像認識による構造の違いについて
(2021/04/27) 去年10月に書いた記事ですが、一般公開にしてなかったのですこし書き加えて公開にしました。 はじめに はじめまして。python、機械学習を学び始めてまだ一年もたっていない駆け出しのエンジニア大学生です。 自分は今アルバイトでよく深層学習による画像分析を行っています。そういった中で、自分はすでに実装されていたネットワークを使ったもで解析をしていたのですが、実際そういうネットワークはどういうものなのか、CNNやネットワークそのものについてはあまり勉強ができていませんでした。 そこで、「そもそもCNNってなんだろう?」、「手法による違いでネットワークの構造ってどう変わってくるのだろう?」 ということについて、自分自身のための勉強も兼ねて記事を書きました。 この記事は自分のようなエンジニア初心者を対象にした記事になります。記事の中で簡単なコードを挟んでいるので、実際に実行してみてCNNやその中身で使われているもの、また論文を読む際に必要な知識についての理解が深まっていただければと思います(数式はまったく使いません)。 間違いもあるかと思いますが、コメント等で指摘をお願いしますm(_ _)m 1. CNN(Convolutional Neural Network)について CNNというのは、畳み込み(Convolution)とプーリング(Pooling)という層が使われたニューラルネットワークのことを指します。CNNの層が深いネットワークのことをDeep Convolutional Neural Network(DCNN)ともいいますが、全体的にCNNと呼ぶ方が一般的です。 ここでは、CNNで使われている畳み込みとプーリングというのはどんな処理が行われているかを例を通して説明していきます。 1.1 畳み込みとは CNNで使われている畳み込み処理は画像処理で使われる空間フィルタリングとほとんど同じです。「空間フィルタリングって何?」と思う方もいるかもしれないので、まず空間フィルタリングについて説明してから畳み込み処理を解説します。 空間フィルタリング 空間フィルタリングというのは、あるサイズのカーネル(空間フィルタともいいます)と、それと同じサイズの画素との内積を取っていくことで、新しい画像データを作る(フィルタされた画像を得る)という手法です。 例えば、次のように3x3ピクセルのフィルタ係数(オレンジ)と5x5の画像データがあるとします。 このフィルタ係数の画像データの青枠で示した部分の各画素値について、同じ成分とを掛け合わせ、それらの和をとります。この操作を畳み込みといいます。 この畳み込みによって得られた値(上図では18)が新しい画素値、つまり特徴量となります。これを1マスずつスライドしていくことによって他の画素に対しても同様に行っていきます。 こうして、新しい特徴量で示された画像データができました。ただし、これで得られる画像は元の画像に対して外枠1マス分だけ小さくなってしまうので、あらかじめ外枠を1マス増やし、増やした領域を0で埋めることで変換前と後で画像サイズが変化しないようにするという方法(ゼロパディングなど)があります。 この一連の操作が空間フィルタリングです。空間フィルタリングでは、このカーネル内の係数を変えることで様々な変換が行うことができます。例として、ソーベルフィルタでは下図のような鹿の画像が中央のカーネルを用いることで右下のようにエッジが抽出された画像に変換できます: (自身の撮影した画像より) サンプルコード import cv2 # 画像の読み込み # フィルタはRGBではなくグレイスケールで読み込ませる img_base = cv2.imread('sample.png', cv2.IMREAD_GRAYSCALE) # ソーベルフィルタ(y)を適用させる sobel_img = cv2.Sobel(img_base, cv2.CV_64F, 0, 1, ksize=3) # ちなみに、x方向では次のようになる # sobel_img = cv2.Sobel(img_base, cv2.CV_64F, 1, 0, ksize=3) # 出力 cv2.imwrite('sobel_sample.png', sobel_img) 畳み込み層 本題です。前項で説明した空間フィルタリングでは、出力は1つのフィルタが施された画像になりますが、CNNでの畳み込み層では、入力から、特徴マップと呼ばれるデータが出力されます。 特徴マップは入力データの中にある特徴的な部分などの情報が入ったデータのことで、鹿の鼻や角だったり、先ほど説明したようなソーベルフィルタで得られるエッジ等の特徴が含まれています。 畳み込み層ではフィルタの数だけカーネルが用意されており、それぞれで空間フィルタリングの処理を行っていくことで、最終的に縦横のサイズ、フィルタ数だけの深さのようなデータが返されます(例えば、出力の縦横が28x28、フィルタ数が32であれば(28,28,32)の3階テンソル)。 ※実際は上のようなきれいなものが得られるわけではないので、VGG16ネットワークの各レイヤの特徴を可視化するなどを参考にしてみてください。) 学習においては、フィルタリングをする際のカーネルのパラメータ(重み行列)とバイアスが学習されます。初期値は任意の重み行列(バイアスも任意)となり、それらを学習によって調整していくことで、最適な出力が得られるようになります。 tf.kerasでは次のように実装されています。画像に対して一般的に使われるのはConv2Dというレイヤーです。時系列データなどにおいてはConv1D、3次元の空間データにはConv3Dなども使われています。 conv2d_layer = tf.keras.layers.Conv2D( filters, kernel_size, strides=1, padding='valid', activation='relu', kernel_initializer='glorot_uniform', bias_initializer='zeros') ) 引数 内容 fileters 出力されるフィルタの数 kernel_size カーネルの大きさ、int型であれば縦横が同じサイズ、tupleであれば指定サイズになります。 strides スライスするときのステップ数。1でスキップなしのスライディングになります。kernel_sizeと同様、int型であれば縦横が同じサイズ、tupleであれば指定サイズになります。 padding 'valid'でなし、'same'で外枠0埋めです。 activation 活性化関数。中間層には'relu'が、出力層は'softmax'が使われるのが一般的です。 kernel_initializer 学習前のカーネルの重み行列の初期化手法を指定します。0埋めや1埋め、乱数など初期化の手法も様々ありますが、活性化関数にreluを使う畳み込み層ではよく'he_normal'が使われています。 bias_initializer 学習前のバイアスの初期化手法を指定します。デフォルトは'zeros'(=0)です。 (他にも引数は存在しますが、話が難しくなるので省略しています。それらは公式ドキュメントを参照してください。) サンプルコード from tensorflow.keras.layers import Conv2D, Input # 28x28x3(28x28, RGB)の入力 x = Input(shape=(28,28,3)) # パディング無し x_nopadding = Conv2D(filters=32, kernel_size=3, strides=1, padding='valid')(x) print(x_nopadding.shape) # バッチサイズ(今回は入力で指定してないのでNone)が加わった4階テンソルが返される # >>(None, 26, 26, 32) # パディングあり x_padding = Conv2D(filters=32, kernel_size=3, strides=1, padding='same')(x) print(x_padding.shape) # >>(None, 28, 28, 32) 1.2 プーリングとは プーリングは畳み込みと比べて非常にわかりやすいです。簡単に言ってしまえば、「指定した領域の中から条件をみたす特徴量を取り出して、特徴マップのサイズを小さくする」になります。プーリングをまとめてダウンサンプリングともいったりします。 平均値プーリング 選択範囲の平均を取ったものを出力します。 tf.kerasではtf.keras.layers.AveragePooling2D()で実装がなされています(公式ドキュメント)。 最大値プーリング 選択範囲の最も大きい値を出力します。 tf.kerasではtf.keras.layers.MaxPooling2D()で実装がなされています(公式ドキュメント)。 プーリンの種類は上記2です。ほかにもGlobalのついたプーリング層(GlobalAveragePooling, GlobalMaxPooling)も存在しますが、それらは層のすべてが対象になるので、全結合層(後述)で使われるものになります。 このようなダウンサンプリングとは対象に、セマンティックセグメンテーション(後述)において用いられているアップサンプリング(tf.keras.Upsampling2D、公式ドキュメント)と呼ばれるものがあります。これは画像の拡大とほとんど同じです。 1.3 プーリング層の必要性 一般的なCNNのエンコーダにはInput→Conv→Pooling→Conv→Pooling→…といった畳み込みとプーリングがセットになったものが多く見られます。 「畳み込みだけで十分じゃないのか?」と僕も初めは思ったことがあったりしましたが、実際はそうは上手くいかないみたいです。 より広範囲の特徴量が得られない 例えば256x256の画像で3x3の畳み込みをすると、そのマスの中の特徴量を見るわけですが。その際得られる特徴量は非常に細かい部分を見たものになります。人間が何かを学ぶ上で小さいところから大きいところまで観察するように、機械学習においても細かい部分だけでなくより局所的な部分の特徴量も必要です。そうでないと、学習が進まなくなったりして精度が悪くなってしまいます。小さいサイズの画像を学習したりする場合はあまり気にすることがないときもありますが、その場合は次ののようなことが起こります。 学習パラメータが多すぎて過学習になる 畳み込みを繰り返すと、学習パラメータの量は増えていきます。パラメータは増えるほど様々な情報をより正確に学習できますが、それだと学習に時間がかかりすぎたり、データに対してパラメータの数が過剰で過学習や学習不足に陥ります。 2020/11/10追記 : コメントの指摘にもある通り、単に多いとダメというわけでなく、層が深いDNN(後述のセマンティックセグメンテーション等)では逆にパラメータが多い方が学習が良くなるケースが多いみたいです。ここは見なかったことにしてください… このように、畳み込みだけで構成するのは過学習や学習不足などの原因になります。ダウンサンプリングをしてから畳み込みを行うことで、より広い範囲の特徴量を取得していく必要があるわけです(ただし、畳み込みは連続して使うのはダメということではなく、プーリングを途中で入れたほうが良いということの意味であることは理解してください)。 2. 画像認識による構造の違いについて CNNはいろんな様式の分類で使われていますが、今回は画像認識の中の「クラス分類」、「物体検出」、「セマンティックセグメンテーション」について説明していきます。 2.1 クラス分類 最も有名な手法の1つです。入力の画像から、その中に何があるかを分類します。入力は画像で、出力はクラス毎の確率になります。 特徴 クラス分類においては、CNN層の出力層の直前で全結合層(Fully connected layer)が使われるのが特徴です。全結合層より前の層では、それまでの画像から得られた特徴量が含まれています、それらを1次元に畳み込むことで、「その画像には何があるか」という情報へと変換できるのです。最終的にクラス数だけのベクトルに変換することで分類の出力になります。 全結合層で使われるものとして、にtf.keras内ではFlatten、DenseまたはGlovalAveragePooling2Dなどがそれにあたります。 Flatten : n階テンソルの形状をを1次元テンソルに変換する(パラメータ数は保持) サンプルコード from tensorflow.keras.layers import Flatten, Input x = Input(shape=(256, 256, 3)) x = Flatten()(x) # 256x256x3=196,608 print(x.shape) # >>> TensorShape([None, 196608]) Dense : 1次元ベクトルのパラメータを指定したパラメータ数へ変換する。入力は1次元であることが必要 サンプルコード from tensorflow.keras.layers import Dense, Input x = Input(shape=(256*256*3, )) x = Dense()(x) print(x.shape) # >>> TensorShape([None, 256]) GlobalAveragePooling2D : n階テンソルの各ベクトルについて、各層の特徴量の平均を求めることで1次元テンソルに変換する(パラメータ数が減る) サンプルコード from tensorflow.keras.layers import GlobalAveragePooling2D, Input x = Input(shape=(256, 256, 3)) x = GlobalAveragePooling2D()(x) print(x.shape) # >>> TensorShape([None, 3]) 例 以下はmnistデータをCNNを使って分類してみた例です。 import numpy as np import tensorflow as tf from tensorflow.keras.datasets.mnist import load_data from tensorflow.keras.models import Model from tensorflow.keras.layers import * from tensorflow.keras.utils import to_categorical # mnistデータを読み込む (train_images, train_labels), (test_images, test_labels) = load_data() # 出力するクラス数 classes = 10 # バッチサイズ batch_size = len(train_images)//16 #60000//16=3750 # エポック epochs = 20 # Functional APIでの実装 # ______________________________________________________________________________________________ # 入力は(28,28,1)のグレイスケール # 学習時は(batch_size, 28, 28, 1)が入力になる。 input_layer = Input(shape=(28,28,1)) # 1つ目の畳み込み x = Conv2D(filters=32, kernel_size=3, strides=1, padding='same', activation='relu')(input_layer) # 最大値プーリング # (28, 28, 32) → (14, 14, 32) x = MaxPooling2D((2,2))(x) # 2つ目の畳み込み x = Conv2D(filters=64, kernel_size=3, strides=1, padding='same', activation='relu')(x) # 最大値プーリング # (14, 14, 64) → (7, 7, 64) x = MaxPooling2D((2,2))(x) # 3つ目の畳み込み # 出力は(7, 7, 64) x = Conv2D(filters=64, kernel_size=3, strides=1, padding='same', activation='relu')(x) # ここから全結合層。Flattenをつかって(3136, )の2次元ベクトルに変換。※7x7x64=3136 x = Flatten()(x) # Denseをつかってサイズ(64, )にする x = Dense(64, activation='relu')(x) # Denseをつかって(classes, )のサイズにする # 活性化関数にsoftmaxを使うことで、出力の各成分は区間[0, 1]で表現される output_layer = Dense(classes, activation='softmax')(x) # ______________________________________________________________________________________________ # 入力層と出力層を引数に入れてmodelを作成 model = Model(input_layer, output_layer) # データの前処理 # 学習データを[0,1]で正規化する train_images = train_images / 255.0 test_images = test_images / 255.0 # ラベルをバイナリクラスに変換する(categorical_crossentropyを使うため) train_labels = to_categorical(train_labels) test_labels = to_categorical(test_labels) # モデルのコンパイル model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) # 学習 model.fit(train_images, train_labels, batch_size=batch_size ,epochs=epochs) # テストデータを使って精度を確かめる test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2) print('\nTest accuracy:', test_acc) 出力: Test accuracy: 0.9883000254631042 有名なもの クラス分類で使われネットワークの例としては、おそらく機械学習を触れたならば必ず聞くであろうこの2つが有名です: VGG16 : 16層からなるDCNNネットワーク ResNet(Residual Network) : 残差ブロックをいう手法を取り入れることで勾配問題に対処した tensorflowでも上記は実装されています。 2.2 物体検出 物体検出とは、入力の画像の中から、その中に何があり、それがどこにあるかが欲しいときに使われる手法です。出力は、分類結果に加えて対象のバウンディングボックス(矩形)を表示するために必要な座標などです。 (自身の撮影した画像より) 特徴 物体検出では、上の画像のように複数の物体のクラスとその位置を出力としてできるのが特徴です(複数でなく、1つの結果とそのバウンディングボックスを検出するものをImage Classification&Localizationともいいます)。 ネットワークの構造の特徴については、すみません、もう少し勉強に時間がかかりそうなのでいつか紹介できればと思います… 参考になるリンクや記事は掲載しておきます。 物体検出についての歴史まとめ(1) 最近のSingle Shot系の物体検出のアーキテクチャまとめ 有名なもの R-CNN(Regions with Convolutional Neural Networks) Faster R-CNN YOLO(You Only Look Once) SSD(Single Shot MultiBox Detector) FPN(Feature Pyramid Networks) 2.3 セマンティックセグメンテーション セマンティックセグメンテーションとは、入力の画像から、その中に何があり、どこにあってどのような形かが必要なときに使われます。物体検出では矩形を用いて物体のクラスとその位置を識別しましたが、セマンティックセグメンテーションでは1ピクセルにつきクラス分類することでそのクラスと形状を検出し、マスク画像が出力となります。 (A Unified Architecture for Instance and Semantic Segmentationより引用) 特徴 構造については、一番わかりやすいUNetで紹介します。 (論文U-Net: Convolutional Networks for Biomedical Image Segmentation Fig.1より少し編集) UNetは、畳み込みとプーリングを繰り返すエンコーダと、アップサンプリングを繰り返すことで元のサイズに戻すencoder-decoderネットワークの構造をしています。 エンコーダの部分は、クラス分類で見られた全結合層を畳み込み層に置き換えたFully Convolutional Network(FCN)という構造を採用しています。出力層で全結合によって1次元にするのではなく、畳み込みを行うことで「物体が何か」という情報から「どこにあるのか」という特徴量が得られるようになるわけです。 デコーダについては、小さくなったマップサイズをUpsamplingという解像度を上げる層と畳み込み層を使うことで元の入力画像サイズへと拡大していきます。 図中の中央の灰色の矢印ですが、これはSkip Connectionと呼ばれるものです。エンコーダでのダウンサンプリング前に得られた特徴量を、デコーダの得られた特徴量とつなげることによって、より精度の高い出力結果が得られるようになります。加えて、層を深くすることで発生しやすくなる過学習などを抑えるなどの効果もあります。 有名なもの UNet PSPNet(Pyramid Scene Parsing Network) : Pyramid Poolingモジュールという手法が特徴 P-FPN(Panoptic FPN) など… これらはsegmentation_modelsですでに実装がされています(サンプルコード参照) サンプルコード # おまじない import os os.environ['SM_FRAMEWORK'] = 'tf.keras' # segmentation_modelsをインポート import segmentation_models as sm # 入力サイズ input_size = (480, 480, 3) # PSPNet pspnet_model = sm.PSPNet( backbone_name='resnet50', # バックボーンの構造(エンコーダの構造)は何を使うか input_shape=input_size, #入力サイズ(縦横は48の倍数であること) encoder_weights="imagenet", # バックボーンの重みは何を使うか # あらかじめ学習済みの重みを使うことで、学習の精度が上げられる classes=3, # 出力される画像内に含まれるラベルの数。つまり(480, 480, classes)のような出力になる activation='softmax') # 出力層の活性化関数。sigmoidかsoftmax # UNet unet_model = sm.Unet( backbone_name='resnet50', input_shape=input_size, #入力サイズ(縦横は48の倍数であること) encoder_weights="imagenet", classes=3, activation='sigmoid') # FPN fpn_model = sm.FPN( backbone_name='resnet50', input_shape=input_size, #入力サイズ(縦横は32の倍数であること) encoder_weights="imagenet", classes=3, activation='softmax') 3. おわり 長い記事になってしまいましたが、参考になっていただければ幸いです。バッチ正規化、最適化のための損失関数やオプティマイザについては触れていなかったので、機会があれば書いてみたいです。 → オプティマイザ、損失関数について記事にしました (学習最適化のための損失関数とOptimizer & MRI画像を使った比較) 畳み込み層については、もしかしたら今回のでは十分理解できないかもしれません。そうであった場合は、Kerasライブラリの作者であるFrancois Chollet氏によって書かれたPythonとKerasによるディープラーニング本を手に取ってみてください。
- 投稿日:2020-10-20T22:57:14+09:00
pythonanywhereにuploadしたDjangoのSQLite3をGUIだけで変更する方法
pythonanywhereにuploadしたDjangoのデータを変更する方法。
コマンドラインを使用せずに、直観的に変更方法の備忘録。やりたかったこと
・しばらく放置していた自身のポートフォリオサイトのアプリのリンク先と画像を久しぶりに更新したかった。変更前の画像
ステップ1
pythonanywhereのコンソール画面を開いて、sqllite3ファイルが置いてあるフォルダまで進む。sqlite3ファイルをダウンロードする。ステップ2
DB Browser(sqlite) を使用して、ダウンロードしたdb.sqlite3ファイルを開く。ステップ3
リンク先と新たな画像名を変更する。変更後、Applyを押す。ステップ4
新しい画像をアップロードする。
pythonanywhereのコンソール画面から、写真の置いてある(staticの設定してある)フォルダまで移動する。
新しい画像をuploadする。
(ステップ3で変更した画像名と一致するようにする。)ステップ5
再度、sqlite3.dbファイルがあるフォルダに移動し、ローカルで書き換えたsqlite3.dbをアップロードして置き換える。
以上で修正完了。
- 投稿日:2020-10-20T22:52:16+09:00
OpenCVで画像切り取りツール作成、射影変換の注意点(少しだけ)
はじめに
OpenCVを使用して画像切り取りツールを作成しました。
対象物を切り取り、射影変換して形を整えた後それぞれを保存します。対象物は以下のような画像にあるフィルムを想定しています。
これでなくても、四角形を抽出する際は使用できると思います。また、作成中に射影変換で躓いたので最後に内容、解決策を記載しています。
詳細環境
Mac OS
python 3.8.5opencv-python 4.4.0.44
numpy 1.19.2
tqdm 4.50.2pip install opencv-python pip install tqdm
プログレスバーを使用する為tqdmをインポートしています。
射影変換
対象物を真正面から撮影したように補正する処理です。
切り取りした画像を直角にしたかったので使用しました。射影変換の参考記事
Python/OpenCVの射影変換なら簡単に画像補正ができる! | WATLAB -Python, 信号処理, AI-
OpenCVを使って画像の射影変換をしてみるwithPython - Qiita全文
画像読み取りに日本語パスも対応させるため以下の記事を参考にしています。
Python OpenCV の cv2.imread 及び cv2.imwrite で日本語を含むファイルパスを取り扱う際の問題への対処について - Qiita操作方法は
1. スクリプトと同じ階層にresourceフォルダ作成
2. resourceフォルダ内に処理したい画像をいれる(複数可, jpg, jpeg or png)
3. 実行結果は"./resultフォルダ/画像ファイル名/画像ファイル名_0,..."と保存されていきます。
ファイル名と同じフォルダがresultに存在していた場合処理をスルーします。うまく切り取りできない場合はthresh_valueかminimum_areaを変更してみて下さい.
画像のしきい値処理 — OpenCV-Python Tutorials 1 documentation
領域(輪郭)の特徴 — OpenCV-Python Tutorials 1 documentationimport os, shutil, time from pathlib import Path import cv2 import numpy as np from tqdm import tqdm thresh_value = 240 # 2値化する時の境界値, これより画素値が小さければ白にする(max:255) minimum_area = 10000 # 輪郭を取得したときにこれより面積が小さい物は処理しない(対象物以外のドットを検出してしまったとき用) def imread(filename, flags=cv2.IMREAD_COLOR, dtype=np.uint8): try: n = np.fromfile(filename, dtype) img = cv2.imdecode(n, flags) return img except Exception as e: print(e) return None def imwrite(filename, img, params=None): try: ext = os.path.splitext(filename)[1] result, n = cv2.imencode(ext, img, params) if result: with open(filename, mode='w+b') as f: n.tofile(f) return True else: return False except Exception as e: print(e) return False def calculate_width_height(pts, add): """ 検出した形状の幅, 高さを三平方を使用して求める あまりに斜めになっていると射影変換したときに形状が変わる為 :parameter ------------ pts: numpy.ndarray 抽出した形状の4点の座標, shape=(4, 1, 2) add: int 形状によって始点の座標が違う為その補正 :return ------------ width: int 幅の計算値 height: int 高さの計算値 """ top_left_cood = pts[0 + add][0] bottom_left_cood = pts[1 + add][0] bottom_right_cood = pts[2 + add][0] width = np.int(np.linalg.norm(bottom_left_cood - bottom_right_cood)) height = np.int(np.linalg.norm(top_left_cood - bottom_left_cood)) return width, height def img_cut(): """ resourceフォルダにある画像(jpg, png)を読み取り対象物の輪郭を取得 対象物を切り取り射影変換して正面に持ってくる 1. フォルダ, ファイル読込 2. 画像読込, 2値化(白黒)処理 3. 輪郭取得 4. 射影変換 5. 出力 6. resourceファイルをresultへ移動 :return: None """ # 1. フォルダ, ファイル読込 resource_folder = Path(r'./resource') result_folder = Path(r'./result') # resultフォルダが存在していなかったら作成 if not result_folder.exists(): result_folder.mkdir() img_list1 = list(resource_folder.glob('*.jpg')) # フォルダ内にあるjpgファイルのpathリスト img_list2 = list(resource_folder.glob('*.jpeg')) img_list3 = list(resource_folder.glob('*.png')) img_list = img_list1 + img_list2 + img_list3 for img in img_list: img_name, img_suffix = img.stem, img.suffix # 画像の名前と拡張子取得 # resultフォルダ内に画像ファイル名でフォルダを作成, 既に同じフォルダが存在している場合変換をスキップ result_img_folder = Path(r'./result/{}'.format(img_name)) if not result_img_folder.exists(): result_img_folder.mkdir() else: print('{}と同じ名前のフォルダがresult内に存在している為変換できません'.format(img_name)) continue # 2. 画像読込, 2値化(白黒)処理 read_img = imread(str(img)) gray_img = cv2.cvtColor(read_img, cv2.COLOR_BGR2GRAY) ret, thresh_img = cv2.threshold(gray_img, thresh_value, 255, cv2.THRESH_BINARY_INV) # -------------------------------------------- # 2値化画像確認用 # cv2.namedWindow('final', cv2.WINDOW_NORMAL) # cv2.imshow('final', thresh_img) # cv2.waitKey(0) # cv2.destroyAllWindows() # -------------------------------------------- # 3. 輪郭取得 # cv2.RETR_EXTERNAL:検出した輪郭のうち、最も外側にある輪郭だけを抽出->輪郭の中に輪郭があってもそれを無視する # cv2.CHAIN_APPROX_SIMPLE:輪郭の辺ではなく、角4点のみ取得 contours, hierarchy = cv2.findContours(thresh_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) process_cnt = [] # 実際に切り取りする輪郭のリスト for cnt in contours: if cv2.contourArea(cnt) < minimum_area: # 輪郭内の面積が小さすぎる物は切り取らない continue process_cnt.append(cnt) num = 0 for p_cnt in tqdm(process_cnt[::-1], desc='{}'.format(img_name)): # 何故か一番下の画像から処理を始めるのでスライスで逆(上)からに直す x, y, w, h = cv2.boundingRect(p_cnt) # 輪郭の左上x, y座標 & 幅, 高さ取得 img_half_width = x + w / 2 # cv2.arcLength: 輪郭の周囲長, Trueは輪郭が閉じているという意味 # cv2.approPolyDP: 検出した形状の近似 epsilon = 0.1 * cv2.arcLength(p_cnt, True) approx = cv2.approxPolyDP(p_cnt, epsilon, True) try: # 4. 射影変換 pts1 = np.float32(approx) if pts1[0][0][0] < img_half_width: # ptsに格納されてある座標の始点が左上だったら width, height = calculate_width_height(pts1, 0) pts2 = np.float32([[0, 0], [0, height], [width, height], [width, 0]]) else: width, height = calculate_width_height(pts1, 1) pts2 = np.float32([[width, 0], [0, 0], [0, height], [width, height]]) except IndexError: continue M = cv2.getPerspectiveTransform(pts1, pts2) dst = cv2.warpPerspective(read_img, M, (width, height)) result_img_name = img_name + '_{}.{}'.format(num, img_suffix) imwrite(str(result_img_folder) + '/' + result_img_name, dst) num += 1 # 6. resourceファイルをresultへ移動 shutil.move(str(img), result_img_folder) if __name__ == '__main__': img_cut() print('実行終了') time.sleep(3)詳細
# cv2.arcLength: 輪郭の周囲長, Trueは輪郭が閉じているという意味 # cv2.approPolyDP: 検出した形状の近似 epsilon = 0.1 * cv2.arcLength(p_cnt, True) approx = cv2.approxPolyDP(p_cnt, epsilon, True) try: # 4. 射影変換 pts1 = np.float32(approx)pts1に対象物の角4点の座標情報が格納されています。
ex)
[[[6181. 598.]][[ 145. 656.]]
[[ 135. 3499.]]
[[6210. 3363.]]]
この4点を画像の角に持ってくることで正面から見たような画像に補正しています。
if pts1[0][0][0] < img_half_width: # ptsに格納されてある座標の始点が左上だったら width, height = calculate_width_height(pts1, 0) pts2 = np.float32([[0, 0], [0, height], [width, height], [width, 0]]) else: width, height = calculate_width_height(pts1, 1) pts2 = np.float32([[width, 0], [0, 0], [0, height], [width, height]])pts1の始点がどこかを判定しています。
格納されている座標4点は最も上にある(y軸が小さい)点を始点に反時計回りに格納されている為、画像の傾きによってpts1の始点が変わります。それを判定して射影変換後の座標pts2と対応させています。
判定方法は始点のx座標が画像中央より左右どちらにいるかで判断しています。
また、対象物の形状はなるべく保持したいため、三平方を使用して幅、高さを計算、そのサイズで切り取り画像を出力しました。
終わりに
pts1の始点が変わることを知らず、最初は意味不明な画像を出力していました。ネットで探してもなかなか見つからず、最後は画像と睨めっこしてようやく分かったという状態でした。
同じように困った方がいた時に参考になれば幸いです。参考サイト
チュートリアル
画像のしきい値処理 — OpenCV-Python Tutorials 1 documentation
輪郭: 初めの一歩 — OpenCV-Python Tutorials 1 documentation
領域(輪郭)の特徴 — OpenCV-Python Tutorials 1 documentationOpenCV参考(輪郭, 画像切り取り, 射影変換)
OpenCVで画像から輪郭検出の基本(findContours関数あたり) | 北館テック.com
輪郭を使用して画像内のオブジェクトを取得およびトリミングする - python、image、opencv-contour
OpenCVを使って画像の射影変換をしてみるwithPython - QiitaOpenCV 日本語パス読書対応
Python OpenCV の cv2.imread 及び cv2.imwrite で日本語を含むファイルパスを取り扱う際の問題への対処について - Qiitanumpy 三平方計算参考
ユークリッド距離を求めるプログレスバー参考
tqdmでプログレスバーを表示させる - Qiita
- 投稿日:2020-10-20T22:48:11+09:00
行列から探してみよう
こんばんは('Д')
いつも応援有難うございます m(_ _)mアルゴリズムを色々書いてきましたが、
ちょっと小休止で行列で遊んでみたくなりました。
簡単な奴から行きます。test.pyimport numpy as np Tarray = np.arange(12) print(Tarray)実行結果.py[ 0 1 2 3 4 5 6 7 8 9 10 11]これって、例えば 3行4列に変更できないのでしょうか?
はい、出来ます。test.pyimport numpy as np Tarray = np.arange(12).reshape(3,4) print(Tarray)実行結果.py[[ 0 1 2 3] [ 4 5 6 7] [ 8 9 10 11]]なるほど~、面白い!!
ここから、特定の要素のみを print するには
どうすれば良いでしょうか?
こんな記述はどうでしょう。。test.pyimport numpy as np Tarray = np.arange(12).reshape(3,4) print(Tarray) print() print(f"Tarray[0,0] is {Tarray[0,0]}")実行結果.py[[ 0 1 2 3] [ 4 5 6 7] [ 8 9 10 11]] Tarray[0,0] is 0なるほど。( ´ー`)y-~~
ここまで分かったら、
行列から、欲しい数字を探せるかも。
やってみましょう(≧▽≦)例えば 2行10列の 1 行目からデータを
抜き取る場合、こんな記述になりませんか?test.pyimport numpy as np Tarray = np.arange(20).reshape(2,10) print(Tarray) num = int(input(": ")) for i in range(10): if Tarray[0,i] == num: print(f"founded data is placed Tarray[0,{i}] ")実行結果.py[[ 0 1 2 3 4 5 6 7 8 9] [10 11 12 13 14 15 16 17 18 19]] : 6 founded data is placed Tarray[0,6]次は行をまたいで検索しましょう。
前述の Tarray[0,i] の 0 を変数に変えれば OK です。test.pyimport numpy as np Tarray = np.arange(20).reshape(2,10) print(Tarray) num = int(input(": ")) for j in range(2): for i in range(10): if Tarray[j,i] == num: print(f"founded data is placed Tarray[{j},{i}] ")実行結果.py[[ 0 1 2 3 4 5 6 7 8 9] [10 11 12 13 14 15 16 17 18 19]] : 13 founded data is placed Tarray[1,3]ではでは、行、列すらも変数になったらどうなるでしょうか。
私はこんな風に書いてみました。matrix_search.pyimport numpy as np M,N = map(int,input("enter M , N: ").split()) atest = np.arange(M*N).reshape(M,N) print(atest) num = int(input("find value: ")) for i in range(M): for j in range(N): if atest[i,j] == num: print(f"found value is placed at [{i},{j}]")実行結果.pyenter M , N: 4 8 [[ 0 1 2 3 4 5 6 7] [ 8 9 10 11 12 13 14 15] [16 17 18 19 20 21 22 23] [24 25 26 27 28 29 30 31]] find value: 20 found value is placed at [2,4]位置表示が 0 行 0 列があるものとして構成しています。
無いですよね、そんなの(笑)matrix_search.pyimport numpy as np M,N = map(int,input("enter M , N: ").split()) atest = np.arange(M*N).reshape(M,N) print(atest) num = int(input("find value: ")) for i in range(M): for j in range(N): if atest[i,j] == num: print(f"found value is placed at [{i+1},{j+1}]")実行結果.pyenter M , N: 4 8 [[ 0 1 2 3 4 5 6 7] [ 8 9 10 11 12 13 14 15] [16 17 18 19 20 21 22 23] [24 25 26 27 28 29 30 31]] find value: 20 found value is placed at [3,5]はい、今度は大丈夫そうです。
ではまた ^^) _旦~~
- 投稿日:2020-10-20T22:38:07+09:00
AWS lambdaを使ってニュースをスクレイピングし、更新分を定期的にLINEに通知してみる【python】
はじめに
今回が初投稿になります。プログラミングを独学で勉強しはじめて半年強ほどの大学生ですが、学んだことを少しずつアウトプットしてみたいと考え、投稿させていただきます。
コードの書き方等雑であったり汚い点が多々あると思いますので、遠慮なく指摘していただいて構いません。目標・手順
タイトルにある通り、AWSのlambdaというツールを使って(Yahooニュースの記事)を定期的(6時間毎)にスクレイピングして、更新された記事について、LINEmessagingAPIを使って自分のLINEアカウントに通知することを目標とします。開発環境はlambdaとの連携を考慮し、cloud9を使います。
手順についてですが、
①PythonのBeautifulSoupモジュールを用いてニュースサイトから記事のタイトルとurlを20件取得、urlはAWSのS3に置いたcsvファイルに書き込む。(書き込む部分はプログラムの最後に行います。)
②前回実行分のurl(S3からcsvを読み込む)と今回取得したurlを比較して、更新分を求める。
③更新分の記事のタイトルとurlをLINEmessagingAPIを用いて通知する。
という順序になります。LINEmessagingAPIについては、LINE BOT で ウェブページの更新監視する
BeautifulSoupでのスクレイピングは、BeautifulSoupを使ったWebスクレイピング
S3のcsvfileの読み込み、書き込みについては、AWS S3のCSVファイルをシンプルに読み込むPythonコードとWrite a Pandas dataframe to CSV on S3あたりの記事を参考にさせていただきました。コード
import urllib.request from bs4 import BeautifulSoup import csv import pandas as pd import io import boto3 import s3fs import itertools from linebot import LineBotApi from linebot.models import TextSendMessage def lambda_handler(event, context): url = 'https://follow.yahoo.co.jp/themes/051839da5a7baa353480' html = urllib.request.urlopen(url) # htmlパース soup = BeautifulSoup(html, "html.parser") def news_scraping(soup=soup): """ 記事のタイトルとurlを取得 """ title_list = [] titles = soup.select('#wrapper > section.content > ul > li:nth-child(n) > a.detailBody__wrap > div.detailBody__cnt > p.detailBody__ttl') for title in titles: title_list.append(title.string) url_list = [] urls = soup.select('#wrapper > section.content > ul > li:nth-child(n) > a.detailBody__wrap') for url in urls: url_list.append(url.get('href')) return title_list,url_list def get_s3file(bucket_name, key): """ S3からcsvを読み取る """ s3 = boto3.resource('s3') s3obj = s3.Object(bucket_name, key).get() return io.TextIOWrapper(io.BytesIO(s3obj['Body'].read())) def write_df_to_s3(csv_list): """ S3に書き込む """ csv_buffer = io.StringIO() csv_list.to_csv(csv_buffer,index=False,encoding='utf-8-sig') s3_resource = boto3.resource('s3') s3_resource.Object('バケット名','ファイル名').put(Body=csv_buffer.getvalue()) def send_line(content): access_token = ******** #Channel access token を記入 line_bot_api = LineBotApi(access_token) line_bot_api.broadcast(TextSendMessage(text=content)) ex_csv =[] #前回スクレイピング分のurlを入れる for rec in csv.reader(get_s3file('バケット名', 'ファイル名')): ex_csv.append(rec) ex_csv = ex_csv[1:] #index=Falseとして書き込んだはずだが読み込んだcsvの先頭に0というインデックス(?)が書き込まれていた ex_csv = list(itertools.chain.from_iterable(ex_csv)) #読み込んだcsvが二次元配列になっていたため一次元に変換 title,url = news_scraping() #スクレイピング実行 csv_list = url #ex_csvと比較して更新分を取り出していく for i in range(20): if csv_list[i] in ex_csv[0]: #完全一致してくれなかったためinを使用 num = i #ex_csvの先頭にある記事がcsv_listの何番目の記事に当たるか調べる break else: num = 'all' if num == 'all': send_list = [None]*2*20 send_list[::2] = title send_list[1::2] = url send_list = "\n".join(send_list) #タイトル、urlを交互に挿入し、改行 elif num == 0: send_list = '新しいニュースはありません' else: send_list = [None]*2*num send_list[::2] = title[:num] send_list[1::2] = url[:num] send_list = "\n".join(send_list) ##タイトル、urlを交互に挿入し、改行 send_line(send_list) csv_list = pd.DataFrame(csv_list) #リストのままS3に書き込むとエラーが出るためデータ型を変換 write_df_to_s3(csv_list) #S3にcsv_listを書き込んで終了コードは以上です。(numからsend_listを作るところは関数を定義した方がよかったですね)
後はremoteにデプロイして、Amazon CloudWatch Eventsで定期実行の設定をしてあげます。特定の時間毎に実行するにはCron式でスケジューリングするのがいいかと思います。
S3へのアクセスはIAMでアクセス権限を付与する必要があるので注意する必要がありますね。おわりに
S3のcsvの読み取り書き込みはなかなか思い通りにいかなかったです。特に書き込む際に二次元配列になってしまったところなど改善する余地がありそうです。
実は以前にselniumやheadless-chromeとlambdaでのスクレイピングを実践したことがあった(lambdaを初めて使用したことに加え、chromebinary関連で山ほどエラーが出て苦労しました。)
ため、今回は比較的短時間でコードを書くことが出来ました。
とはいえ、ローカル内のスクレイピングと比べるとかなり作業量が多くなりますね。lambdaの使い方はここでは省いていますが、かなりややこしいので他の記事を参照してみてください。最近はdjangoやTwitterAPIなどに手を出しているので、このあたりで何か気づいた点があればまた投稿しようと考えています。
ありがとうございました。
- 投稿日:2020-10-20T20:22:25+09:00
Python 簡単に使える関数
最近、Pythonの学習を進めています。
まだまだ初歩の学習中ですが、覚えた関数が増えてきたので備忘録としてまとめます。
組み込み関数
組み込み関数 = 最初からPythonの機能として使える関数
下記のリストに対していくつかの組み込み関数を使っていきます。
nums = [100, 200, 500, 1000, 500]sum() → 合計した数字を返す
print(sum(nums)) → 2300max() → 最大値を返す
print(max(nums)) → 1000min() → 最小値を返す
print(min(nums)) → 100len() → 要素数(文字数)を返す
print(len(nums)) → 5str() → 数字を文字列に変換
print(str(nums)) → [100, 200, 500, 1000, 500] #文字列として出力されるインポートしたモジュールの関数
モジュール = Pythonの定義や文が入ったファイル
モジュールをインポートすることで、定義されている関数を使うことができます。
例として random モジュールを利用します。
import random nums = [199, 288, 56, 82, 99, 1, 538, 499]randint(n, m) → 指定した範囲(n~m)の整数をランダムに返す
print(random.randint(1, 100)) → 17choice() → 指定したリスト内の要素1つをランダムに返す
random.choice(nums) → 288shuffle() → 指定したリストの順番をランダムに返す
random.shuffle(nums) → [56, 499, 538, 199, 99, 288, 1, 82]関数の定義
def 文で定義します。
例として平均を求める関数を自作します。
(平均値はstatisticsモジュールの mean() で求められますが。)def average(nums): return sum(nums) / len(nums) nums = [10, 100, 30, 43, 57, 34, 90, 76] result = average(nums) print(result) → 55.0インデントされている部分のみ、関数の処理となります。
参考
https://docs.python.org/ja/3/library/functions.html
https://docs.python.org/ja/3/library/numeric.html
https://docs.python.org/ja/3/library/random.html
- 投稿日:2020-10-20T14:06:01+09:00
GANの出力を1枚ずつ保存する 〜PyTorchによるGANの実装とともに〜
卒業研究でGANを扱う中で、GANの生成する画像を1枚ずつ保存する必要が出てきました。
しかし、調べても調べてもGANの実装をしている記事はどれもこんな感じの出力ばかり…
このような複数枚まとめての出力ではなく、これらが1枚ずつ出力されるようにしました。
備忘録も兼ねて記しておきます。目的
GANの実装を行う&GANの生成画像を1枚ずつ保存する
GAN
GAN(Generative Adversarial Network):敵対的生成ネットワークはIan J. Goodfellow氏が提案した生成モデルです。
Generative Adversarial Nets2つのネットワークを有していて、お互いに競い合いながら学習を進めていきます。
Generator:生成器はDiscriminator:判別器を騙せるような画像を生成し、Discriminatorは本物の画像か偽物の画像かを判別していきます。
GANを一躍有名にしたDCGANや驚くほどリアルな画像を生成するStyleGANなど様々なアーキテクチャが提案されています。GANの実装
それではGANの実装に移っていきます。今回は先ほどのDCGANの実装を行っていきます。
実装の参考にしたコードはこちら実行環境
Google Colaboratory
import&ディレクトリ作成
import argparse import os import numpy as np import torchvision.transforms as transforms from torchvision.utils import save_image from torch.utils.data import DataLoader from torchvision import datasets import torch.nn as nn import torch os.makedirs("./images", exist_ok=True)必要なモジュールをインポートしていきます。今回はPyTorchで実装を行っていきます。
GANの出力画像を保存するディレクトリも作成します。exist_ok=True
となっているので、既にディレクトリが存在する場合はスルーされます。コマンドライン引数&デフォルト値の設定
コマンドラインでepoch数やバッチサイズなどの値を指定できるようにします。同時にデフォルトの値も設定します。
epoch数やバッチサイズなどについてはこちらの記事がわかりやすいと思います。parser = argparse.ArgumentParser() parser.add_argument("--n_epochs", type=int, default=200, help="number of epochs of training") parser.add_argument("--batch_size", type=int, default=64, help="size of the batches") parser.add_argument("--lr", type=float, default=0.0002, help="adam: learning rate") parser.add_argument("--b1", type=float, default=0.5, help="adam: decay of first order momentum of gradient") parser.add_argument("--b2", type=float, default=0.999, help="adam: decay of first order momentum of gradient") parser.add_argument("--n_cpu", type=int, default=8, help="number of cpu threads to use during batch generation") parser.add_argument("--latent_dim", type=int, default=100, help="dimensionality of the latent space") parser.add_argument("--img_size", type=int, default=32, help="size of each image dimension") parser.add_argument("--channels", type=int, default=1, help="number of image channels") parser.add_argument("--sample_interval", type=int, default=400, help="interval between image sampling") opt = parser.parse_args() print(opt)コマンドラインを使用できる環境ならこのままでいいのですが、Google Colaboratoryで実装を行う場合は以下のようなエラーが発生してしまいます。
usage: ipykernel_launcher.py [-h] [--n_epochs N_EPOCHS] [--batch_size BATCH_SIZE] [--lr LR] [--b1 B1] [--b2 B2] [--n_cpu N_CPU] [--latent_dim LATENT_DIM] [--img_size IMG_SIZE] [--channels CHANNELS] [--sample_interval SAMPLE_INTERVAL] ipykernel_launcher.py: error: unrecognized arguments: -f /root/.local/share/jupyter/runtime/kernel-ecf689bc-740f-4dea-8913-e0d8ac0b1761.json An exception has occurred, use %tb to see the full traceback. SystemExit: 2 /usr/local/lib/python3.6/dist-packages/IPython/core/interactiveshell.py:2890: UserWarning: To exit: use 'exit', 'quit', or Ctrl-D. warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)Google Colabでは
opt = parser.parse_args()
の行をopt = parser.parse_args(args=[])
としてあげると無事通ります。CUDAの設定と重みの初期化
cuda = True if torch.cuda.is_available() else False def weights_init_normal(m): classname = m.__class__.__name__ if classname.find("Conv") != -1: torch.nn.init.normal_(m.weight.data, 0.0, 0.02) elif classname.find("BatchNorm2d") != -1: torch.nn.init.normal_(m.weight.data, 1.0, 0.02) torch.nn.init.constant_(m.bias.data, 0.0)GPUを使用しないと学習に相当時間かかってしまうのでCUDA(GPU)を使用できるようにします。Google Colabではランタイムの設定をGPUに変更するのを忘れないでください。
Generator
Geberator:生成器のネットワークを定義します。
class Generator(nn.Module): def __init__(self): super(Generator, self).__init__() self.init_size = opt.img_size // 4 self.l1 = nn.Sequential(nn.Linear(opt.latent_dim, 128 * self.init_size ** 2)) self.conv_blocks = nn.Sequential( nn.BatchNorm2d(128), nn.Upsample(scale_factor=2), nn.Conv2d(128, 128, 3, stride=1, padding=1), nn.BatchNorm2d(128, 0.8), nn.LeakyReLU(0.2, inplace=True), nn.Upsample(scale_factor=2), nn.Conv2d(128, 64, 3, stride=1, padding=1), nn.BatchNorm2d(64, 0.8), nn.LeakyReLU(0.2, inplace=True), nn.Conv2d(64, opt.channels, 3, stride=1, padding=1), nn.Tanh(), ) def forward(self, z): out = self.l1(z) out = out.view(out.shape[0], 128, self.init_size, self.init_size) img = self.conv_blocks(out) return imgDiscriminator
Discriminator:判別器のネットワークを定義します。
class Discriminator(nn.Module): def __init__(self): super(Discriminator, self).__init__() def discriminator_block(in_filters, out_filters, bn=True): block = [nn.Conv2d(in_filters, out_filters, 3, 2, 1), nn.LeakyReLU(0.2, inplace=True), nn.Dropout2d(0.25)] if bn: block.append(nn.BatchNorm2d(out_filters, 0.8)) return block self.model = nn.Sequential( *discriminator_block(opt.channels, 16, bn=False), *discriminator_block(16, 32), *discriminator_block(32, 64), *discriminator_block(64, 128), ) # The height and width of downsampled image ds_size = opt.img_size // 2 ** 4 self.adv_layer = nn.Sequential(nn.Linear(128 * ds_size ** 2, 1), nn.Sigmoid()) def forward(self, img): out = self.model(img) out = out.view(out.shape[0], -1) validity = self.adv_layer(out) return validity損失関数の設定とネットワーク周りの設定
# Loss function adversarial_loss = torch.nn.BCELoss() # Initialize generator and discriminator generator = Generator() discriminator = Discriminator() if cuda: generator.cuda() discriminator.cuda() adversarial_loss.cuda() # Initialize weights generator.apply(weights_init_normal) discriminator.apply(weights_init_normal) # Optimizers optimizer_G = torch.optim.Adam(generator.parameters(), lr=opt.lr, betas=(opt.b1, opt.b2)) optimizer_D = torch.optim.Adam(discriminator.parameters(), lr=opt.lr, betas=(opt.b1, opt.b2)) Tensor = torch.cuda.FloatTensor if cuda else torch.FloatTensorDataLoaderの作成
DataLoaderを作成していきます。今回はMNISTデータセットを用いて画像生成を行います。
MNIST:手書き数字の画像データセット# Configure data loader os.makedirs("./data/mnist", exist_ok=True) dataloader = torch.utils.data.DataLoader( datasets.MNIST("./data/mnist",train=True,download=True, transform=transforms.Compose([ transforms.Resize(opt.img_size), transforms.ToTensor(), transforms.Normalize([0.5], [0.5])] ), ),batch_size=opt.batch_size,shuffle=True, )Training
いざGANのTrainingを行っていきます。
# ---------- # Training # ---------- for epoch in range(opt.n_epochs): for i, (imgs, _) in enumerate(dataloader): # Adversarial ground truths valid = Tensor(imgs.shape[0], 1).fill_(1.0) fake = Tensor(imgs.shape[0], 1).fill_(0.0) # Configure input real_imgs = imgs.type(Tensor) # ----------------- # Train Generator # ----------------- optimizer_G.zero_grad() # Sample noise as generator input z = Tensor(np.random.normal(0, 1, (imgs.shape[0], opt.latent_dim))) # Generate a batch of images gen_imgs = generator(z) # Loss measures generator's ability to fool the discriminator g_loss = adversarial_loss(discriminator(gen_imgs), valid) g_loss.backward() optimizer_G.step() # --------------------- # Train Discriminator # --------------------- optimizer_D.zero_grad() # Measure discriminator's ability to classify real from generated samples real_loss = adversarial_loss(discriminator(real_imgs), valid) fake_loss = adversarial_loss(discriminator(gen_imgs.detach()), fake) d_loss = (real_loss + fake_loss) / 2 d_loss.backward() optimizer_D.step() print( "[Epoch %d/%d] [Batch %d/%d] [D loss: %f] [G loss: %f]" % (epoch, opt.n_epochs, i, len(dataloader), d_loss.item(), g_loss.item()) ) batches_done = epoch * len(dataloader) + i if batches_done % opt.sample_interval == 0: save_image(gen_imgs.data[:25], "images/%d.png" % batches_done, nrow=5, normalize=True)実行結果
一定間隔で結果が保存されるので実行結果をGIF画像で見ていきます。
人が見てもきちんとわかる数字たちが生成されています。
画像を1枚ずつ保存したい
こんな人なかなかいないと思うのですが、調べてもなかなか出てこなかったので共有します。
上記のTrainingの部分にあったif batches_done % opt.sample_interval == 0: save_image(gen_imgs.data[:25], "images/%d.png" % batches_done, nrow=5, normalize=True)この部分を以下のように変更すれば1枚ずつ保存できます。
if batches_done % opt.sample_interval == 0: save_gen_img = gen_img[0] save_image(save_gen_imgs, "images/%d.png" % batches_done, normalize=True)1枚ずつ複数枚保存自体場合はfor文でも使って欲しい枚数文
save_image
を繰り返せば大丈夫だと思います。訓練時間はグッと増えますが
これで最初の目的であったGANの出力を1枚づつ保存することを達成しました。まとめ
今回はPyTorchでDCGANの実装を行うとともに、GANの出力を1枚ずつ保存できるようにし、実際に手書きの数字が生成されていることを確認できました。
次はGANの出力を制御できるconditional GAN(cGAN)について書いていこうと思います。cGANも同様にクラスごとに1枚ずつ画像が保存できるようにしていきます。
- 投稿日:2020-10-20T13:36:06+09:00
バイナリ法
バイナリ法
$x=a^k$のとき,2乗計算を$k$回行うことになる.
計算を効率よくする方法として,$a^{2^i}$を順次求めることで,計算量を$log(k)$回に抑える方法がバイナリ法である.具体例
$5^{21}=5^{2^4}*5^{2^2}*5^{2^0}$
2進数に展開し,左から順に展開することにより計算を実行する.
これにより,$g^k(mod p)$を計算する.アルゴリズム
binary.pydef Binary(k, g, p): k_binary = [] while(k != 0): k_binary.append(k%2) k = k//2 if k == 1: k_binary.append(k) k = 0 y = 1 for i in reversed(range(len(k_binary))): if k_binary[i] == 1: y = (y*y%p)*g%p else: y = (y*y%p) return y
- 投稿日:2020-10-20T13:26:07+09:00
numpyの基本的でないテクニック
numpyのクイックスタートチュートリアルにLess basic(あまり基本的でない)テクニックがあり面白そうと思ったので、理解ついでに紹介。
配列を用いた、配列のインデックス
配列のインデックス(a[i]におけるiの部分)にはスカラー値を持つことが一般的ですが、ここに配列を入れることもできます。
import numpy as np a = np.arange(12)**2 i = np.array([1, 1, 3, 8, 5]) a[i] #array([ 1, 1, 9, 64, 25], dtype=int32)何が起こっているのかというと、図のようになります。
配列iの要素がインデックスとなり、それを用いてaの配列から抽出してくるイメージでしょうか。
インデックスが2次元配列でも適用することができます。その場合、出力も2次元になります。
j = np.array([[3, 6, 7], [5, 9, 7]]) a[j] #array([[ 9, 36, 49], # [25, 81, 49]], dtype=int32)チュートリアルの方ではRGBを応用例として出していますが、機械学習で使われるone-hot表現の際にも使えそうですね。
one_hot = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]]) number = np.array([[0, 1, 2, 0], [0, 3, 2, 0]]) one_hot[number] #array([[[0, 0, 0], # [1, 0, 0], # [0, 1, 0], # [0, 0, 0]], # # [[0, 0, 0], # [0, 0, 1], # [0, 1, 0], # [0, 0, 0]]])ちなみに、
number[one_hot[number]]
としても元に戻るわけではないので注意。また、インデックスには複数の配列を指定することもできます。
a = np.arange(12).reshape(3,4) #array([[ 0, 1, 2, 3], # [ 4, 5, 6, 7], # [ 8, 9, 10, 11]]) i = np.array([[0, 1], [1, 2]]) j = np.array([[2, 1], [3, 3]]) a[i, j] #array([[ 2, 5], # [ 7, 11]])これまたどう処理しているのか解釈が難しいところですが、以下のようになっています。
配列のインデックスには、リストを指定することもできます。
a = np.arange(3,8) a #array([3, 4, 5, 6, 7]) a[[1,3,4]] = 0 a #array([3, 0, 5, 0, 0])このときも、リストの各要素がaのインデックスとして処理されます。
リストを使って一気に割り当てる(代入する)こともできますが、リスト内に同じ数値がある場合、割当ては繰り返されて最後の値が代入されます。
a = np.arange(3,8) a #array([3, 4, 5, 6, 7]) a[[1,1,4]] = [1,2,3] a #array([3, 2, 5, 6, 3])ブール配列を使用したインデックス付け
配列に論理演算子を与えることで、ブール配列を作ることができます。
ブール配列をインデックスとすることで、Falseとなる要素を取り除いた1次元配列を出力します(配列の形に注意)。
a = np.arange(-3,9).reshape(3,4) a #array([[-3, -2, -1, 0], # [ 1, 2, 3, 4], # [ 5, 6, 7, 8]]) b = a > 0 b #array([[False, False, False, False], # [ True, True, True, True], # [ True, True, True, True]]) a[b] #array([1, 2, 3, 4, 5, 6, 7, 8])ブール配列をインデックスとする配列に割り当てることで、条件に合った要素へ一度に代入することができます。
a[a<0] = 0 a #array([[0, 0, 0, 0], # [1, 2, 3, 4], # [5, 6, 7, 8]])次元(軸)と同じブール配列を使うことで、より複雑な抽出もできます。
a = np.arange(12).reshape(3,4) b1 = np.array([False,True,True]) b2 = np.array([True,False,True,False]) a[b1,:] #a[b1]でも可 #array([[ 4, 5, 6, 7], # [ 8, 9, 10, 11]]) a[:,b2] #a[b2]でも可 #array([[ 0, 2], # [ 4, 6], # [ 8, 10]]) a[b1,b2] #array([ 4, 10])図としてみるとこんなかんじ。
これ、なんでa[b1,b2]が[[4,6],[8,10]]じゃなくて[4,10]なんでしょうね。ドキュメントにもa weird thing to do(奇妙なこと)と書いてあるので、そう覚えるしかないのでしょうか。
まとめ
以上、配列を用いた配列のインデックスと、ブール配列を使用したインデックス付けについて紹介しました。扱いの難しいテクニックですが、使いこなせばきっと役に立つはずです。
冒頭にリンクを貼ったチュートリアルには、他にもテクニックが載っている(うまく理解できなかったため割愛)ので、余裕のある人はぜひ読んでみてください。
- 投稿日:2020-10-20T12:21:06+09:00
テンソルネットワークを用いた量子インスパイアな機械学習
はじめに
今回は、近年少しホットになっている量子インスパイア機械学習を紹介します。
ここでの"量子インスパイア"をもう少し正確に言うと、"量子系を古典計算でなるべく効率的にシミュレートするために用いられる手法から着想を得た"です。
具体的にはテンソルネットワークです。背景
古典系による量子系のシミュレートにテンソルネットワークを用いる流れは以前からありました。多体量子系の状態を行列積状態を用いて効率的に計算する[1]、ゲート量子計算を無向グラフとテンソルネットワークの縮約の組み合わせで効率的にシミュレートする[2]、などです。
これらの手法が示すように、テンソルネットワークを用いることで量子系が持つ非常に高次元の空間をあくまで近似的にですが、古典計算で扱うことができます。
高次元であることは機械学習においては表現力の高さにつながります。この特徴を量子系のシミュレートだけでなく古典機械学習問題に適用しようというのが今回紹介する"量子インスパイアな機械学習"となります。
行列積状態(復習)
行列積状態はMPSと呼ばれ、下記図のように表されます[1]。
各黒丸は"site"と呼ばれ、N qubit系であればN個のsiteが作られます。
$\sigma_i$は"physical index"と呼ばれ、qubitの場合は$0\ (|0\rangle)$ or $1\ (|1\rangle)$を指します。各siteは通常の2次元行列にphysical indexの次元を加えた3次元行列(テンソル)と考えます。各siteはそれぞれphysical index=0に対応する2次元行列と、physical index=1に対応する2次元行列を持つとイメージすることもできます。
仮に全ての$i$について$\sigma_i = 0$の場合、全てのsiteのphysical index=0に対応する2次元行列同士の積を計算することができ、その結果はもとの量子状態における$|00...0>$の係数となります。どのように機械学習を行うか
教師あり学習による分類問題を扱った代表的な論文[3],[4]をもとに紹介します。
全体的なフローを図に示します。まず、入力データ$x$を行列積状態の図の$\sigma_i\ (i\in 0,...,n-1)$にエンコードします。
エンコードしたデータとMPSとの間でテンソル縮約をとります。
さらにMPSのsite間のエッジを縮約するのですが、このままでは得られるのは1つのスカラー値なので分類に使えません。
そのためMPSにはあらかじめ、$x$が各クラスに属する確率に対応する値を出力するための"label index"を持たせておきます。label indexは既存のsite 1つ、またはlabel indexの保持用に新たに追加したsite 1つに持たせます。
このようにすると、$\sigma_i$とMPSのすべてのエッジの縮約を計算した結果、判別クラス数と要素数の等しいテンソルが残るためその値を損失関数に入力できます。学習時は損失関数の出力が小さくなるよう、MPSの各要素を更新します。
更新の方針は大きく分けて2通りあります。
1つは[3]で採用されている方法で、DMRGという従来の手法の応用です。隣り合う2 siteのみを変数とした局所的な最適化による更新をsweepしながら繰り返します。
もう1つは[4]で採用されており、誤差逆伝搬法を用いてMPSの全要素を更新します。前者の手法は更新の際にSVDを用いて余剰次元を動的に刈り込めるメリットがあります。
一方後者の手法は既存のDL, 自動微分フレームワークによる計算との相性が良く、またおそらくネットワーク構造や損失関数の定義などの自由度が高いです。実装
今回は[4]で行われた、誤差逆伝搬法によるMNIST学習を実装しました。
実装には著者らが開発したTensornetworkというpythonモジュールを使用しました。Tensornetworkは文字通りテンソルネットワークの計算に適したライブラリです。
バックエンドとして"tensorflow"と"jax"を選択できます。"tensorflow"を選択した場合はTensorflowフレームワークと組み合わせて学習できます。
Tensorflowの自動微分機能や組み込みの関数を使用できる点が便利なのですが、一方で書いてみるとほとんどがカスタムレイヤーで占められてしまうため、フレームワークに合わせて書く面倒さやフレームワーク自体のオーバーヘッドが気になる面もあります。そこで今回はjaxバックエンドを採用しています。
実際に[4]に続く研究[5]ではjaxバックエンドを使用しているようです。
jaxもpythonフレームワークで、おおざっぱに言うと自動微分、JIT、ベクトル化による並列演算をサポートしたnumpyのようなものです。
Tensorflowの高速な自動微分だけシンプルに使いたい、という場合に良い選択肢なのではないでしょうか(JuliaのFluxなども似たような立ち位置だと思っていて、そういった需要はそれなりにあるのでしょう)。私の実装は[4]とは以下の点でやや異なっています。
1. MNISTの画像データを2x2 average poolingしている。
2. optimizerは[4]で使用されたadamでなく単純な勾配降下法(それに伴い、学習率やEpoch数も調整)1.については、オリジナルのサイズだと学習の難易度が高かったためです。縮約をとる際に行われるのは画素数分の行列のかけ算であり、かける行列の数が増えると出力値が発散 or 0収束しやすい、また勾配が消失しやすいなどのプラクティカルな難しさがあります。調整次第ではあると思うのですが今回は妥協しました。
また[5]では(ネットワーク構造やタスクがいくらか異なるためかもしれないですが)著者らもpoolingしています。2.はサンプル実装をシンプルにするためです。
また手元でtensorflowバックエンドで書いた時にadam optimizerでトライした結果と比較して、勾配降下法が特に劣っていなかったという経緯もあります。実装コードは以下に置きました。
https://github.com/ryuNagai/MPS/blob/master/TN_ML/MNIST_ML_jax.ipynb
※初回学習実行時、JITコンパイルが3分くらいかかります。どこか改善の余地ありかもしれません。最終的にtrain accuracy=0.962、test accuracy=0.952となりました。
[4]では50 epoch程度でtrain accuracy=0.98程度に到達しており、それを再現するには及ばない結果でした。
裏では[4]の結果が再現できないか条件近くして多少試したのですが、中々難しかったので一旦この値で良しとします。まとめ
新たに流行る(かもしれない)テンソルネットワークを用いた量子インスパイア機械学習を実装しました。
量子コンピュータのハードウェア面に多くの制約がある現状で、こちらの手法は古典計算機上で実行できるため大きな問題も扱えます。
この手法を用いて従来の機械学習モデルより有用なモデルが多く発見されるかはまだこれからの研究次第だと思います。加えて、古典機械学習と比較した優位性が量子空間を用いた機械学習にあるかどうか、このような手法を用いることでそれが近似的・間接的にでも見える、検証できる可能性があれば良いと思っています。
参考文献
[1] https://arxiv.org/abs/1008.3477
[2] https://arxiv.org/abs/1805.01450
[3] https://papers.nips.cc/paper/6211-supervised-learning-with-tensor-networks
[4] https://arxiv.org/abs/1906.06329
[5] https://arxiv.org/abs/2006.02516
- 投稿日:2020-10-20T12:12:07+09:00
Pythonでメタアナリシス
はじめに
PythonにはPythonMetaというメタ分析を行うパッケージもあるのですが、勉強の意味も兼ねて、今回はpandasでメタアナリシスを実装してみました。
メタアナリシスのモデルには主に Fixed Effect Model (固定効果モデル) と Random Effects Model (変量効果モデル) の2種類があるので、それぞれ実装してみます。
サンプルデータ
今回は、以下のデータを使って実験してみます。
import pandas as pd import numpy as np data = pd.DataFrame({ "g": [0.12, 0.23, 0.34, 0.45, 0.42, 0.39, 0.49, 0.65, 0.76, 0.87], "V": [0.01, 0.04, 0.03, 0.02, 0.01, 0.02, 0.03, 0.04, 0.02, 0.01] })ここで g が Hedges'g (=効果量)、Vが効果量の分散を表しています。
固定効果モデル
固定効果モデルではシンプルに効果量の分散の逆数をその項目の重みとします。したがって求める平均効果量はそれぞれの項目の効果量に重みをかけたものを全体の重みで割ったものとして計算されます。計算式は以下の通りです。Pythonでも3行で書けtしまいます。
# 固定効果モデル data['W'] = 1 / data.V data['Wg'] = data['g'] * data['W'] result = data['Wg'].sum() / data['W'].sum() result >> 0.4776変量効果モデル
変量効果モデルでは重みを計算する部分が少し複雑になります。研究間の効果量のばらつきを考慮するために、一旦効果量の平均をとったうえで、それに対する各項目の偏差を重みの計算に組み込みます。計算式は以下の通りです。
g_hat = data.g.mean() Q = (data.W * (data.g - g_hat)**2).sum() data['W2'] = data.W ** 2 C = data.W.sum() - (data.W2.sum()/data.W.sum()) d = len(data) - 1 # 研究間分散 if (Q-d) > 0: V_between = (Q - d) / C else: V_between = 0 data['V_str'] = data.V + V_between data['W_str'] = 1 / data.V_str result = (data.g * data.W_str).sum() / data.W_str.sum() resultその他
固定効果モデルでも変量効果モデルでも、計算された重みの和から95%信頼区間を計算することができます。
std_err = np.sqrt(1/data.W_str.sum()) lwr = result - 1.96 * std_err upr = result + 1.96 * std_err [lwr, upr]参考文献
- 投稿日:2020-10-20T12:07:37+09:00
Machine Learning : Supervised - Random Forest
目標
ランダムフォレストを理解して、scikit-learn で試す。
理論
ランダムフォレストは、複数の決定木を組み合わせるバギングと呼ばれるアンサンブル学習の 1つです。
ノーフリーランチ定理
ノーフリーランチ定理とは、元々は組み合わせ最適化において、考え得るすべての問題に探索アルゴリズムを適用した場合、その平均性能はどのアルゴリズムも同じようなものになるというものです。
これは、各アルゴリズムにはそれぞれ満たすべき前提条件があり、考え得るすべての問題がその前提条件を満たすことはないため、ある問題に対しては良い成果を発揮しても、別の問題では他のアルゴリズムよりも悪い性能になってしまうことから、すべての問題で他のアルゴリズムよりも良いアルゴリズムはないことを示しています。
そこから発展して、機械学習においてはどんな問題でも最良の結果が得られる万能な学習器が存在しないことを主張する際に引用されます。
バギング
前述のノーフリーランチ定理により、どんな問題にも最適な万能な学習器は存在しないことが分かっています。そこで、複数の学習器を組み合わせるという方法を思いつくのは自然な発想です。
複数の学習器からの出力の多数決を取って最終的な出力とするといった学習法はアンサンブル学習と呼ばれています。アンサンブル学習に使用される個々の識別器は、ランダムより少し良い程度の性能であればよいので、弱識別器と呼ばれています。
アンサンブル学習の代表的な方法として、バギング (Boostrap AGGregatING) があります。バギングは、下図のように学習データのブートストラップサンプルを用いて複数の識別器を学習させ、新しいデータに対しては分類では多数決によりカテゴリーを、回帰ではその平均により推定値を出力します。
バギングは個々の識別器を独立に並列で学習することができますが、ブートストラップサンプリングでは重複を許しているため弱識別器として決定木を用いると決定木同士の相関が高くなり、どれも似通ったものになってしまう可能性があります。
このような問題を改善したのがランダムフォレストです。
ランダムフォレスト
ランダムフォレストの学習では、ブートストラップサンプルで決定木を学習する際、すべての特徴量を用いるのではなく、指定しておいた数だけ特徴量をランダムに選択し、その特徴量を用いて決定木を構築します。
バギングではブートストラップサンプルから決定木を構築していましたが、ランダムフォレストでは下図のようにブートストラップサンプルにおいて使用する特徴量をランダムに選択して決定木を構築します。
このように各ブートストラップサンプルにおいて使用する特徴量をランダムにすることによって各決定木が多様性をもつようになり、バギングで問題となっていた決定木間の相関を減らすことが期待できます。
scikit-learn では引数 n_estimators で弱識別器の数を、引数 max_features で使用する特徴量の数を指定することができます。使用する特徴量の数はデフォルトでは特徴量の平方根数を使用するようになっています。
実装
実行環境
ハードウェア
・CPU Intel(R) Core(TM) i7-6700K 4.00GHz
ソフトウェア
・Windows 10 Pro 1909
・Python 3.6.6
・matplotlib 3.3.1
・numpy 1.19.2
・scikit-learn 0.23.2実行するプログラム
実装したプログラムは GitHub で公開しています。
random_forest.py結果
ランダムフォレストによる分類
これまでに使用してきた breast cancer dataset にランダムフォレストを適用した結果を示します。
Accuracy 92.98% Precision, Positive predictive value(PPV) 94.03% Recall, Sensitivity, True positive rate(TPR) 94.03% Specificity, True negative rate(TNR) 91.49% Negative predictive value(NPV) 91.49% F-Score 94.03%下図は、iris dataset に対して多クラス分類を実行した際の識別境界を表しています。
ランダムフォレストによる回帰
回帰問題のデータは正弦波に乱数を加えました。回帰では平均値を最終的な出力値にします。
参考
1.11.2. Forests of randomized trees
- Leo Breiman, "Random forests", Machine learning 45.1 (2001): pp. 5-32.
- 平井有三.『はじめてのパターン認識』,森北出版,2012.
- 投稿日:2020-10-20T10:49:27+09:00
Julia早引きノート[08]変数の型(Int, Float, Bool, Char, String)
変数の型(Int, Float, Bool, Char, String)(書き方例)
note08◆数字の型 Int Int8 Int16 Int32 Int64 Int128 UInt UInt8 UInt16 UInt32 UInt64 UInt128 Float Float16 Float32 Float64 ◆真偽の型 Bool ◆文字列の型 Char String ◆型の確認 typeof()解説
- Int型
- Int型は符号付き整数型で、Int8,Int16,Int32,Int64,Int128があります。
- Int8は8ビット、Int16は16ビット、同様に32ビット、64ビット、128ビットです。
- UInt
- UInt型は符号無し整数型です。
- Bool
- Bool型は true または false です。
- Float
- Float型は浮動小数点です。
- 文字列型
- Charは一文字の型を表します。
- Stringは一連の文字列の型を表します。
もくじ
Julia早引きノート[01]変数・定数の使い方
Julia早引きノート[02]算術式、演算子
Julia早引きノート[03]複素数
Julia早引きノート[04]正規表現
Julia早引きノート[05]if文
Julia早引きノート[06]ループ処理
Julia早引きノート[07]try, catch, finally
Julia早引きノート[08]変数の型(Int, Float, Bool, Char, String)(※引き続きコンテンツを増やしていきます)
関連情報
Julia - 公式ページ
https://julialang.org/Julia - 日本語公式ドキュメント
https://julia-doc-ja.readthedocs.io/ja/latest/index.html初めてのJuliaとインストール (Windows & Linux)
https://qiita.com/ttlabo/items/b05bb43d06239f968035Julia - Mathematics
https://docs.julialang.org/en/v1/base/math/ご意見など
ご意見、間違い訂正などございましたらお寄せ下さい。
- 投稿日:2020-10-20T10:02:59+09:00
【Python】iterdir()など使用時に出る[Errno 20] Not a directory: '***/.DS_Store'
Pythonでiterdir()などを使うと、タイトルのようなエラーが出てきます。
Mac独自の.DS_Storeという隠しファイルのせいで、関数が実行できない時出てきます。
対処としては、.DS_Storeを消せば良いだけです。そもそも.DS_Storeとは
.DS_Store は、Finderがフォルダの設定を記録するためのファイルです。
参考サイト対処
ファインダーでもコマンドラインでもいいので消します。
コマンドラインの場合、
邪魔な.DS_Storeが入っているフォルダに移動しfind . -name ".DS_Store" -deleteで消します。
参考サイト終了です。
- 投稿日:2020-10-20T09:12:23+09:00
【Python】 指定した期間の日時リスト作成
やりたいこと
2020年10月29日 05:00から2020年11月1日 00:00の期間で6時間間隔のリストを作成したい
pythonコード
from datetime import datetime, timedelta def perdate(start, end, delta): current = start while current < end: yield current current += delta for result in perdate(datetime(2020, 10, 29, 5,0,0), datetime(2020, 11, 1, 0,0,0), timedelta(hours=6)): print (result)実行結果
2020-10-29 05:00:00 2020-10-29 11:00:00 2020-10-29 17:00:00 2020-10-29 23:00:00 2020-10-30 05:00:00 2020-10-30 11:00:00 2020-10-30 17:00:00 2020-10-30 23:00:00 2020-10-31 05:00:00 2020-10-31 11:00:00 2020-10-31 17:00:00 2020-10-31 23:00:00参考記事
- 投稿日:2020-10-20T09:00:36+09:00
JuliaでNumPyのadd.atを再現してみる
タイトルそのまま。
再現したいNumPyのコード
NumPyではin-placeな変更である。
Python(NumPy)>>> A = np.ones((3,3)) >>> A array([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]]) >>> B = np.array([[1, 1, 1], [2, 2, 2]]) >>> B array([[1, 1, 1], [2, 2, 2]]) >>> np.add.at(A, [0, 2], B) >>> A array([[2., 2., 2.], [1., 1., 1.], [3., 3., 3.]])Juliaのコード
+=
演算子に.
演算子を付加して.+=
とし,ブロードキャストを行っていることに注意。
+=
はブロードキャストを行わず,in-placeな変更ではない。
しかし,.+=
では(当然)ブロードキャストを行うが,in-placeな変更である1。Juliajulia> A = ones(3,3) 3×3 Array{Float64,2}: 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 julia> B = [1. 1. 1.; 2. 2. 2.] 2×3 Array{Float64,2}: 1.0 1.0 1.0 2.0 2.0 2.0 julia> selectdim(A, 1, [1, 3]) .+= B 2×3 view(::Array{Float64,2}, [1, 3], :) with eltype Float64: 2.0 2.0 2.0 3.0 3.0 3.0 julia> A 3×3 Array{Float64,2}: 2.0 2.0 2.0 1.0 1.0 1.0 3.0 3.0 3.0Sources
numpy.ufunc.at — NumPy v1.19 Manual
Arrays · The Julia Language
Multi-dimensional Arrays · The Julia Language
Mathematical Operations and Elementary Functions · The Julia Language
- 投稿日:2020-10-20T08:04:51+09:00
人生曲線を python で描いてみる
タイトル通りです.
人生曲線とは,これまでの自分の経験を時系列で振り返り,
x軸を年齢,y軸をモチベーション(幸福度,充実度)として,プロットしたものです.次に,y軸が高くなっていくところ,低くなっていくところ,に着目し,
なぜそのようになったのかを繰り返すことで,自分の本質的な価値観が分かる,という仕掛けです.記載のコードの使い方は,自分の経験に合わせて,
x
,y
のデータを改変し,
「ああ,そうそうこんな感じ」というようなグラフが出力される次数を探します.lifeCurveimport numpy as np import matplotlib.pyplot as plt x = np.array([15.0, 16.5, 18.0, 21, 24.0, 25, 26, 27, 28, 29, 30, 33, 35, 37, 45, 53, 62]) y = np.array([15.0, 10.0, 20.0, 30, 24.0, 20, 15, 12, 10, 18, 25, 40, 50, 100, 70, 80, 120]) xp = np.linspace(min(x), max(x), 1000) plt.rcParams["font.size"] = 20 fx = np.poly1d(np.polyfit(x, y, 6)) # ← 次数はいま6.ここを調整. fig, ax = plt.subplots(figsize=(20,10)) ax.plot(xp, fx(xp), '-', color='blue') ax.scatter(x, y, color='deepskyblue', s=32) ax.axhline([0], color='black') ax.set_xlim(min(x), None) ax.set_ylim(0, 1.2*max(y)) ax.set_ylabel('Motivation Level') ax.set_xlabel('My age') color = '#1e90ff' p1 = np.linspace(20, 23) ax.fill_between(p1, fx(p1), 0, facecolor=color, alpha=0.5) p2 = np.linspace(28, 40) ax.fill_between(p2, fx(p2), 0, facecolor=color, alpha=0.5) p3 = np.linspace(50, 60) ax.fill_between(p3, fx(p3), 0, facecolor=color, alpha=0.5) fig.savefig('./data/img/lifeCurve.png'))
- 投稿日:2020-10-20T07:54:23+09:00
PHPでファイルをダウンロードする【作成中】
- 投稿日:2020-10-20T07:40:37+09:00
内挿と外挿の範囲をpythonで可視化
内挿と外挿の範囲を理解するために作ったコード.
過学習への注意も必要だが,外挿の範囲において,
得られた近似式が適用可能かどうかは十分に吟味しないといけない.また,近似する目的が「予測」ではなく,「分析」である場合,
必要以上に変数を多くしたり,次数を上げると,解釈が難しくなるので,
如何に簡単,というかシンプルに仕立てられるか,が課題(腕の見せ所?).赤破線部:外挿範囲,青実線部:内挿範囲 としています.
interpolation_and_extrapolationimport numpy as np import matplotlib.pyplot as plt x = np.array([2.0, 3.5, 4.0, 4.5, 5.0, 5.5]) y = np.array([3.0, 3.2, 3.9, 5.2, 8.4, 10.5]) xp = np.linspace(2, 5.5, 100) xp1 = np.linspace(0, 2, 100) xp2 = np.linspace(5.5, 8, 100) for val in range(1, 6): fx = np.poly1d(np.polyfit(x, y, val)) plt.rcParams["font.size"] = 20 fig, ax = plt.subplots(figsize=(15, 10)) ax.plot(xp, fx(xp), '-', color='blue') ax.plot(xp1, fx(xp1), '-', color='red', linestyle='dashed') ax.plot(xp2, fx(xp2), '-', color='red', linestyle='dashed') ax.scatter(x, y, color='deepskyblue', s=32) s = '$y =$' for idx, deg in enumerate(reversed(range(0, val+1))): if (fx.coef[idx] > 0) & (idx != 0): s += '$ +$' if deg > 1: s += f' ${fx.coef[idx]:.2f} x^{deg}$' if deg == 1: s += f' ${fx.coef[idx]:.2f} x$' if deg == 0: s += f' ${fx.coef[idx]:.2f}$' # ax.text(0.05, 0.8, s=s, size='x-large', transform=ax.transAxes) ax.axhline([0], color='black') ax.axvline([2], color='gray', linestyle='dotted') ax.axvline([5.5], color='gray', linestyle='dotted') ax.set_xlim(0, 8) ax.set_ylim(-3, 14) ax.set_title(s) ax.set_ylabel('response variable') ax.set_xlabel('explanatory variables') fig.savefig(f'./data/img/inter_and_extrapolation{val}.png')
- 投稿日:2020-10-20T06:47:20+09:00
__name__
test.pyprint(__name__)出力__main__
test2.pyimport test出力test
test.pyを直接実行するとnameにstr型のmainが代入される。
またtest.pyを外部からインポートするとstr型のファイル名testが代入される。つまり、if __name__ == '__main__': main()のmain()は外部からインポートされた場合は実行されず、直接実行した場合のみ実行される。
- 投稿日:2020-10-20T04:36:45+09:00
【Python】Gitubのipynbファイルを日本語に翻訳してダウンロードするnotebook
はじめに
前回、プログラムのコメントを日本語に翻訳するスクリプトを書きましたが、同じ要領でipynbファイル(Jupyterのファイル)ごと翻訳できるだろうということで書いてみました。
Githubに上げといたのでColaboratoryから実行できるようにリンクを張っておきます。→ ipynbTranslator.ipynb - Colaboratory使い方
- 投稿日:2020-10-20T04:36:45+09:00
【Python】GitHubのipynbファイルを日本語に翻訳してダウンロードするnotebook
はじめに
前回、プログラムのコメントを日本語に翻訳するスクリプトを書きましたが、同じ要領でipynbファイル(Jupyterのファイル)ごと翻訳できるだろうということで書いてみました。
GitHubに上げといたのでColaboratoryから実行できるようにリンクを張っておきます。→ ipynb_translator.ipynb - Colaboratory使い方
- 投稿日:2020-10-20T02:34:22+09:00
goodnote5のフラッシュカードをAnkiに取り込む
自己紹介
趣味でプログラムを書いている学生。for文がわかる。
環境
macOS Catalina 10.15.7
python 3.8.6動機
goodnotes5でフラッシュカードを作ってAnkiで学習したい。
goodnotes5にあるフラッシュカードの試験的な機能は今のところイマイチ。流れ
3,4番をpythonでやる。
1. goodnotes5からフラッシュカード(下の画像)をイメージ形式で書き出す
2. 書き出したイメージ(いっぱい)を任意のディレクトリに格納しておく
3. 書き出したイメージを2分割してそれぞれをAnkiのcollection.mediaに保存
4. 2分割したイメージをAnkiで表示できるようなcsvファイルを作成する(example.csv)
5. PC版Ankiでcsvをimportするexample.csv<img src="example_qst0.png"><img src="example_ans0.png"> <img src="example_qst1.png"><img src="example_ans1.png"> <img src="example_qst2.png"><img src="example_ans2.png">実際のコード
命名規則、英文法わかりません。
path/to/以下は環境に合わせて変更する。toAnki.pyimport os from PIL import Image # Anki用csv作成のため宣言 Anki_csv = [] # Ankiのメディアファイルの場所 anki_media_path = '/path/to/collection.media' # 画像ファイルの入ったフォルダを指定 print('tell me target dir under homedir') target_dir_path = '/path/to/userhome'+input() # 画像ファイルの名前を指定 print('tell me image file name') image_file_name = input() # 画像ファイルの名前を指定 print('tell me image index start') index = int(input()) # 指定したフォルダ内の画像ファイルを全て取得 target_list = os.listdir(target_dir_path) target_list.remove('.DS_Store') # 各画像ファイルごとに画像処理・保存 for target in target_list: # 画像ファイルをImageオブジェクトに格納 img = Image.open(target_dir_path + '/' + target) # 画像の幅と高さを取得 width = img.size[0] height = img.size[1] # 画像を上と下に分割・保存 img_qst = img.crop((0, 0, width, height/2)) img_ans = img.crop((0, height/2, width, height)) img_qst.save(anki_media_path + '/' + image_file_name + '_qst' + str(index)+ '.png') img_ans.save(anki_media_path + '/' + image_file_name + '_ans' + str(index)+ '.png') # csv用 qst_tag = '<img src="' + image_file_name + '_qst' + str(index)+ '.png' + '">' ans_tag = '<img src="' + image_file_name + '_ans' + str(index)+ '.png' + '">' Anki_csv.append(qst_tag + ',' + ans_tag + '\n') # 終わったら逐一報告 print('done ' + str(index)) # 保存する画像ファイルのインデックスをカウント index += 1 # csv作成 with open('/path/to/Desktop/toAnki.csv',mode='w') as f: for j in Anki_csv: f.write(j) print('All work was done')さいごに
markdown難しい。コードの中身について言及していない。
質問・ご指摘等よろしく。
- 投稿日:2020-10-20T02:34:22+09:00
goodnotes5とAnkiの連携を助けるスクリプトをを書いた
自己紹介
趣味でプログラムを書いている学生。for文がわかる。
環境
macOS Catalina 10.15.7
python 3.8.6動機
goodnotes5でフラッシュカードを作ってAnkiで学習したい。
goodnotes5にあるフラッシュカードの試験的な機能は今のところイマイチ。流れ
3,4番をpythonでやる。
1. goodnotes5からフラッシュカード(下の画像)をイメージ形式で書き出す
2. 書き出したイメージ(いっぱい)を任意のディレクトリに格納しておく
3. 書き出したイメージを2分割してそれぞれをAnkiのcollection.mediaに保存
4. 2分割したイメージをAnkiで表示できるようなcsvファイルを作成する(example.csv)
5. PC版Ankiでcsvをimportするexample.csv<img src="example_qst0.png"><img src="example_ans0.png"> <img src="example_qst1.png"><img src="example_ans1.png"> <img src="example_qst2.png"><img src="example_ans2.png">実際のコード
命名規則、英文法わかりません。
path/to/以下は環境に合わせて変更する。toAnki.pyimport os from PIL import Image # Anki用csv作成のため宣言 Anki_csv = [] # Ankiのメディアファイルの場所 anki_media_path = '/path/to/collection.media' # 画像ファイルの入ったフォルダを指定 print('tell me target dir under homedir') target_dir_path = '/path/to/userhome'+input() # 画像ファイルの名前を指定 print('tell me image file name') image_file_name = input() # 画像ファイルの名前を指定 print('tell me image index start') index = int(input()) # 指定したフォルダ内の画像ファイルを全て取得 target_list = os.listdir(target_dir_path) target_list.remove('.DS_Store') # 各画像ファイルごとに画像処理・保存 for target in target_list: # 画像ファイルをImageオブジェクトに格納 img = Image.open(target_dir_path + '/' + target) # 画像の幅と高さを取得 width = img.size[0] height = img.size[1] # 画像を上と下に分割・保存 img_qst = img.crop((0, 0, width, height/2)) img_ans = img.crop((0, height/2, width, height)) img_qst.save(anki_media_path + '/' + image_file_name + '_qst' + str(index)+ '.png') img_ans.save(anki_media_path + '/' + image_file_name + '_ans' + str(index)+ '.png') # csv用 qst_tag = '<img src="' + image_file_name + '_qst' + str(index)+ '.png' + '">' ans_tag = '<img src="' + image_file_name + '_ans' + str(index)+ '.png' + '">' Anki_csv.append(qst_tag + ',' + ans_tag + '\n') # 終わったら逐一報告 print('done ' + str(index)) # 保存する画像ファイルのインデックスをカウント index += 1 # csv作成 with open('/path/to/Desktop/toAnki.csv',mode='w') as f: for j in Anki_csv: f.write(j) print('All work was done')さいごに
markdown難しい。コードの中身について言及していない。
質問・ご指摘等よろしく。
- 投稿日:2020-10-20T02:31:36+09:00
【Python・Jupyter】クリップボードにコピーしたプログラムのコメントを翻訳して新しいセルに挿入する
はじめに
日本語訳のないライブラリのドキュメントを読むときなど、地味に解釈に苦労することなどありますよね。
英語をスラスラ読めない方だとブラウザの機能で翻訳することが多いと思いますが、コメントだけでいいのにプログラム部分まで翻訳されてしまうのは困りものです。そこで、Jupyter Notebook用にコメント部分だけ翻訳して、
どうせならシンタックスハイライト機能も活かしたいということで、新しいセルに貼り付けるごくシンプルなコードを書いてみました。コード
from googletrans import Translator import re import pyautogui import pyperclip as ppc translator = Translator() pyautogui.hotkey('b', 'enter') code = ppc.paste() en = re.findall("#\s*(.+?)\n", code) ja = [translator.translate(e, dest="ja").text for e in en] for e, j in zip(en, ja): code = code.replace(e, j) ppc.copy(code) pyautogui.hotkey('ctrl', 'v')使用した様子
元コード
What is PyRPL?# import pyrpl library import pyrpl # create an interface to the Red Pitaya r = pyrpl.Pyrpl().redpitaya r.hk.led = 0b10101010 # change led pattern # measure a few signal values print("Voltage at analog input1: %.3f" % r.sampler.in1) print("Voltage at analog output2: %.3f" % r.sampler.out2) print("Voltage at the digital filter's output: %.3f" % r.sampler.iir) # output a function U(t) = 0.5 V * sin(2 pi * 10 MHz * t) to output2 r.asg0.setup(waveform='sin', amplitude=0.5, frequency=10e6, output_direct='out2') # demodulate the output signal from the arbitrary signal generator r.iq0.setup(input='asg0', # demodulate the signal from asg0 frequency=10e6, # demodulaltion at 10 MHz bandwidth=1e5) # demodulation bandwidth of 100 kHz # set up a PID controller on the demodulated signal and add result to out2 r.pid0.setup(input='iq0', output_direct='out2', # add pid signal to output 2 setpoint=0.05, # pid setpoint of 50 mV p=0.1, # proportional gain factor of 0.1 i=100, # integrator unity-gain-frequency of 100 Hz input_filter = [3e3, 10e3]) # add 2 low-passes (3 and 10 kHz) # modify some parameters in real-time r.iq0.frequency += 2.3 # add 2.3 Hz to demodulation frequency r.pid0.i *= 2 # double the integrator unity-gain-frequency # take oscilloscope traces of the demodulated and pid signal data = r.scope.curve(input1='iq0', input2='pid0', duration=1.0, trigger_source='immediately')
In[2]
のセルを実行するとその下のセルが自動で生成されます。
- 投稿日:2020-10-20T02:14:15+09:00
AmazonのデータをKeepAPIを使って取得しよう #1データの取得
アマゾンデータを取得する
仕事でアマゾン(US)のデータを取得する必要が出たため備忘録のため。
商品概要、レビューに関してはスクレイピングでも取得はできると思うのですが
過去の出品状況や価格・ランキングなどは取得できないので
KeepaAPIを使って取得していきます。参考:Keepa
https://keepa.com/#!apiPythonによるデータ取得加工
keepa_analysis.py#ライブラリー !pip install keepa import keepa import pandas as pd #データ取得 accesskey = '##############' # APIkeyを取得し入力してください api = keepa.Keepa(accesskey) products = api.query('B07VQJ5P3L') # ここにはASINを入れるとデータを勝手に取ってくれます keepa.plot_product(products[0])
- 投稿日:2020-10-20T00:17:30+09:00
Chainerによる機械学習のためのPython学習メモ 10章 Cupy 入門
What
Chainerを利用して機械学習を学ぶにあたり、私自身が、気がついた点、リサーチした内容をまとめる記事になります。今回は、scikit-learnを勉強します。
私の理解に基づいて記述しているため、間違っている場合があります。間違いは都度修正するつもりです、ご容赦ください。
Content
GPU
画像処理に特化した演算装置。CPUと原理上何が異なっていて画像処理に有利なのか全く理解できていない。
例えば、下記サイトではCPUとGPUの違いが簡単に説明されている
https://www.datadock.co.jp/column/GPU/2018/05/88.html
ただ本質的な理解をするためには、まずCPUが得意とする処理、GPUが得意とする処理を抑える必要がありそうだ。
定正的な話だけをするなら、似たような処理を同時に複数行うのは現在、並列演算が高速化を可能とする領域であること。数値計算を並列かつ高速に処理できるのがGPUということだけはわかった。
ちなみに、GPUのメーカーNDIVIAは最近ひそやかに注目を浴びていてAIの流れが大きいみたいですね。
CupyではGPUを必要としますが、なんとColabではGPUも使用可能とのこと、すごい!Cupy
内容読んでも、正直そんなにまとめることがないです。。。
Cupyで記述することでGPUで数値計算することができ、高速動作が期待できる。
できるだけ数値計算はNumpyではなくCupyを使って記述することで高速動作するコードがかける。書き方に困ったら適宜調べるという形で大丈夫そうComment
気温がガクッと下がり体調を崩しやすい時期ですね、、、
土日は頭痛と眠気が酷く、寝こんでしまいましたorz