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

ESP32のBLEのRSSIを調べてみた

ESP32のBLEのRSSIを調べてみた 研究の一環として,ESP-WROOM-32を用いてRSSI値の測定をやってみました. 使用機材 ESP32-DevKitC 4台 Mac book Pro (Big Sur) 環境構築 筆者は日頃Python3を用いてコードを書いているので,今回はmicropythonを使っています. ESP32でmicropythonを使う場合はこちらを参照してください. https://micropython-docs-ja.readthedocs.io/ja/latest/esp32/tutorial/intro.html エディタやIDEはお好みで大丈夫ですが,作成したコードをESP32に焼く際はesp-idfを用いるのが楽だと感じました. クイックリファレンスがGithubに上がっていますので,興味がある方はぜひ. https://github.com/espressif/esp-idf BLEのRSSI取得方法 公式のGithubのコードを参考にさせていただきました. https://github.com/micropython/micropython 参考にさせていただいたのは,example > bluetooth内のコードです. 送信側の処理 送信側はble_advertising.pyとble_temperature.pyをそのまま使用しています. 受信側の処理 まず,ble_advertising.pyのdemo()を自分の環境に合わせて変更してください. def demo(): payload = advertising_payload( name="micropython", services=[bluetooth.UUID(0x181A), bluetooth.UUID("XXXX")], ) #送信側のUUIDに設定 筆者はMongoDBにデータを格納しているので以下のようなコードになりました. xxxの部分は適時変更してください. import ubluetooth import utime import ubinascii import urequests import ujson import network, urequests, utime from machine import Pin, RTC from micropython import const _IRQ_SCAN_RESULT = const(5) _IRQ_SCAN_DONE = const(6) def send_db(name,addr,rssi): url = 'http://xxxxxxx' now = get_jst() payload = { "db": "xxx", "collection": "xxx", "datetime": now, "data": { "name": name, "addr": ubinascii.hexlify(addr), "rssi": rssi, } } header = { 'Content-Type' : 'application/json' } res = urequests.post( url, data = ujson.dumps(payload).encode("utf-8"), headers = header ) res.close() def get_jst(): rtc = RTC() url_jst = "http://worldtimeapi.org/api/timezone/Asia/Tokyo" retry_delay = 5000 response = urequests.get(url_jst) parsed = response.json() datetime_str = str(parsed["datetime"]) year = int(datetime_str[0:4]) month = int(datetime_str[5:7]) day = int(datetime_str[8:10]) hour = int(datetime_str[11:13]) minute = int(datetime_str[14:16]) second = int(datetime_str[17:19]) subsecond = int(round(int(datetime_str[20:26]) / 10000)) rtc.datetime((year, month, day, 0, hour, minute, second, subsecond)) daysOfTheWeek = "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" tm = utime.localtime(utime.mktime(utime.localtime())) date_str = "{0:4d}/{1:02d}/{2:02d}".format(*rtc.datetime()) time_str = "{4:02d}:{5:02d}:{6:02d}".format(*rtc.datetime()) date_ok = date_str + " " + time_str return date_ok ble=ubluetooth.BLE() if ble.active()== False: ble.active(True) def bt_irq(event, data): if event == _IRQ_SCAN_RESULT: addr_type, addr, connectable, rssi, adv_data = data name = "xxx" addr_hex = ubinascii.hexlify(addr) if '{}'.format(ubinascii.hexlify(addr)) == 'b\'xxxxx\'': print('addr:{} rssi:{} '.format(ubinascii.hexlify(addr), rssi )) send_db(name, str(addr_hex), rssi) elif event == _IRQ_SCAN_DONE: print('Scan compelete') pass ble.irq(bt_irq) ble.gap_scan(600000, 30000, 30000) ble.gap_scan()に関する詳しい説明はubluetoothのリファレンスを読んでみてください. https://micropython-docs-ja.readthedocs.io/ja/latest/library/ubluetooth.html RSSIの測定 受信側,送信側それぞれをESP32に焼き,実行してみましょう. 筆者はWebREPLを使用しています. WebREPLの使用手順 ①左上のIPアドレスを変更し,Connect! ②右上からファイルを選択し,Send to device! ③以下のコマンドを実行! >>> execfile("xxx.py") 3つのビーコンで測定 各ビーコンで1mの時をそれぞれ測定すると以下のような分布になりました! なお,縦軸は取得回数,横軸はRSSI値です. しっかり測定はできましたが,それぞれで誤差がかなりありそうですね... おわりに ESP32は機器ごとにも誤差が大きいようで,しっかりとした基準値をうまく決めないと使えないようですね... 位置精度の改善や座標の特定など色々な用途に使用できそうですね!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

目覚めを検知する目覚まし時計(スマートアラーム)

はじめに 朝苦手でいつも出勤ギリギリまで寝てしまうので、絶対に起きれる環境をソフトウェアで作ろうと思い、カメラから目覚めを検知するまでアラームが鳴り続ける目覚まし時計をRaspberryPiで作成しました。 目覚め検知には以下の記事で作成した眠気検知プログラムを使用しています。 ラズパイカメラによる眠気検知とWebストリーミング 本記事のソースコードは以下に置いています。 https://github.com/AkitoArai709/SmartAlarm 環境 Raspberry Pi 4 Camera Module V2 For raspberry pi ROUNDS portable speaker Python : 3.7.3 opencv : 4.5.1.48 dlib : 19.22.0 imutils : 0.5.4 scipy : 1.6.2 システム構成  設定されたアラーム時間になるとスピーカーからアラームを鳴らし、カメラを起動します。カメラから人物を検知し、顔の目の大きさから眠気状態を検知し、目覚め状態になるまでアラームを鳴らし続けます。 ファイル構成 . ├─ models │ ├─ dlib │ │ └─ shape_predictor_68_face_landmarks.dat │ └─ opencv │ └─ haarcascade_frontalface_alt2.xml ├─ settings │ └─ alarmSettings.json ├─ sounds │ └─ <Alarm sound file>.wav └─ src ├─ alarmSetting.py ├─ alarmSpeaker.py ├─ buffer.py ├─ detectionSleepiness.py ├─ main.py └─ smartAlarm.py スマートアラーム  main.pyではsmartAlarm.pyで実装されたスマートアラームアプリケーション(SmartAlarmクラス)を読み込んで実行します。 main.py #!/usr/bin/env python """ main.py Summay: RaspberryPi smart alarm application. """ from smartAlarm import SmartAlarm def main(): alarm = SmartAlarm() if __name__ == '__main__': main() smartAlarm.py """ smartAlarm.py Summay: Smart Alarm application. This alarm will continue to sound until wake up. """ import json import time import threading from alarmSetting import AlarmSetting from alarmSpeaker import AlarmSpeaker from datetime import datetime class SmartAlarm: """ SmartAlram. """ __SETTINGS_FILE = "./settings/alarmSettings.json" def __init__(self): """ Init constructor. """ self.__isRunning = False self.__threadObj = None self.__alarmSettings = [] self.alarmSpeaker = AlarmSpeaker() self.readJson() self.startAlarmThread() def __del__(self): """ Destructor. """ self.stopAlarmThread() self.writeJson() def addAlarmSetting(self, time: time, days: list): """ Add Alarm setting. (Example) addAlarmSetting(datetime.strptime("07:00", '%H:%M').time(),['Sun','Mon','Tue','Web','Thu','Fri']) Args: time (time): Alarm time. days (list): Days of the weeks. """ setting = AlarmSetting(time.replace(second=0, microsecond=0),days) self.__alarmSettings.append(setting) def startAlarmThread(self): """ Start AlarmThread. """ self.__isRunning = True if self.__threadObj is None: self.__threadObj = threading.Thread(target=self.__alarmThread) self.__threadObj.start() def stopAlarmThread(self): """ Stop AlarmThread. """ self.__isRunning = False if self.__threadObj is not None: self.__threadObj.join() self.__threadObj = None def writeJson(self): """ Write the alarm settings to json file. """ # Serialize the AlarmSetting object. list = [] for alarm in self.__alarmSettings: if isinstance(alarm, AlarmSetting): alarm: AlarmSetting = alarm list.append(alarm.serialize()) # Convert to json, write file. with open(self.__SETTINGS_FILE, mode='w', encoding='utf-8') as file: json.dump(list, file, indent = 2) def readJson(self): """ Read the alarm settings to json file. """ with open(self.__SETTINGS_FILE, mode='r') as file: list = json.load(file) for setting in list: alarmSetting = AlarmSetting.deserialize(setting) if alarmSetting is not None: self.__alarmSettings.append(alarmSetting) def __alarmThread(self): """ Main thread of SmartAlarm class. Check the alarm settings. If it matches the setting time, go off the alarm. """ while self.__isRunning: if self.__checkAlram(): self.alarmSpeaker.goOff() # Sleep until next time. time.sleep(60 - datetime.now().second) def __checkAlram(self) -> bool: """ Check the alarm settings Returns: (bool): Judgment value of check the alarm settings. """ retVal = False now = datetime.now() for alarm in self.__alarmSettings: if isinstance(alarm, AlarmSetting): alarm: AlarmSetting = alarm # Check the alarm setting if alarm.isSetTime(now): retVal = True alarm.setEnabled(False) return retVal  SmartAlarmクラスはインスタンス生成時にアラーム再生クラス(AlarmSpeaker)のインスタンス生成、アラーム設定ファイル読み込み、アラームスレッドの起動を行い、アプリケーションの動作を開始します。__alarmThreadスレッドではアラーム設定のチェック及び、アラームの再生処理の呼び出しを行います。また、アラーム設定時間は分単位としているため、アラーム時間のチェック処理実行完了後、次の分単位の時間になるまでSleepさせて、CPU使用率が無駄に増加しないように抑制しています。  アラーム設定時間はAlarmSettingクラスで定義され、__alarmSettingsのリストで管理します。リストで管理することで、複数個のアラームを設定可能としています。 アラーム設定クラス  AlarmSettingクラスではアラーム設定として、アラーム時間と曜日を定義します。 alarmSetting.py """ alarmSetting.py Summay: Alarm setting. """ from datetime import datetime, time class AlarmSetting: """ AlarmSetting. """ # Define properties. __PROP_TIME = "time" __PROP_DAYS = "days" __PROPERTIES = [__PROP_TIME, __PROP_DAYS] # Reset time of alarm setting. __RESET_TIME = datetime.strptime("00:00", '%H:%M').time() def __init__(self, time: datetime, days: list): """ Init constructor. """ # self.time = time # self.days = days self.__dict__[self.__PROP_TIME] = time self.__dict__[self.__PROP_DAYS] = days self.__isEnabled = True self.__isAlreadyReset = False @property def time(self) -> time: """ time property. Returns: (time): datetime.time """ return self.__dict__[self.__PROP_TIME] @property def days(self) -> list: """ days property. Returns: (list): days of week. """ return self.__dict__[self.__PROP_DAYS] def isSetTime(self, now: datetime) -> bool: """ Check the setting time. Args: now (datetime): Current time. Returns: (bool): Judgment value of check the alarm setting. """ self.__resetEnabledSetting(now.time()) return self.__isSettingTime(now.time()) \ and self.__isSettingDay(now.strftime('%a')) \ and self.__isEnabled def setEnabled(self, enabled: bool): """ Set the enabled value. Args: enabled (bool): Setting value. """ self.__isEnabled = enabled def serialize(self) -> dict: """ Serialize the AlarmSetting object. Return the dict type of the defined property. Returns: retVal (dict): Serialized value. """ retVal = {} for key, value in self.__dict__.items(): # Only defined properties. if self.__PROPERTIES in key: # The time type does not support json. # Convert time to str. if isinstance(value, time): retVal[key] = value.strftime('%H:%M') else: retVal[key] = value return retVal @classmethod def deserialize(cls, dict: dict): """ Deserialize the AlarmSetting object. Create the myself class from the dict data. Args: dict (dict): Setting data. Returns: (AlarmSetting): myself object. """ # Return None if there is no defined property in the dict data. for prop in cls.__PROPERTIES: if prop not in dict: return None return cls(datetime.strptime(dict[cls.__PROP_TIME], '%H:%M').time(), dict[cls.__PROP_DAYS]) def __isSettingTime(self, time: time) -> bool: """ Check the setting time. Args: time (time): Current time. Returns: (bool): Judgment value of check the setting time. """ return time.replace(second=0, microsecond=0) == self.time def __isSettingDay(self, day: str) -> bool: """ Check the setting day of the week. Args: day (str): Current day of the week. Returns: (bool): Judgment value of check the setting day of the week. """ return day in self.days def __resetEnabledSetting(self, time: time): """ Reset the enabled value. Args: time (time): Current time. """ time = time.replace(second=0, microsecond=0) # Matche the reset time and not yet reset. # Execute the reset process only during the reset time. if time == self.__RESET_TIME \ and self.__isAlreadyReset == False: # Reset process. # Set enabled. self.setEnabled(True) self.__isAlreadyReset = True elif time != self.__RESET_TIME \ and self.__isAlreadyReset == True: # Set false isAlreadyReset flg. self.__isAlreadyReset = False  このクラスではserializeとdeserializeを用意してjson形式の変換を行えるようにしています。json形式の変換にはクラスの辞書型変数である__dict__を用い、変換対象のプロパティを__PROPERTIESで定義を行っています。こうすることで、json変換したいプロパティに変更があった場合でも、定数定義を変数するだけでプロパティを増減できる設計としています。  isSetTime関数でアラーム有効度リセット(__resetEnabledSetting)と、現在日時・曜日のチェックを行い、全て一致時にTrueを返します。  __resetEnabledSetting関数ではリセット時間(00:00)になると、アラームの有効度をTrueにして、アラーム実行で無効(Flase)なった設定を日付の変わるタイミングで有効(True)に戻します。また、Trueを設定する処理だけでは、アラーム時間がリセット時間と重なっている場合に、関数の使い方によっては、 「アラーム実行(Flaseを設定)」→「有効度リセット(Trueを設定)」→「有効度がTrueのため、アラーム実行」... と、同じ時間に複数回アラームが再生される可能性があるため、リセット時間に一度だけTrueを設定するようにしています。 アラーム設定ファイル  アラーム設定として、アラーム時間(time)と曜日(days)をjson形式で定義します。 alarmSetting.json [ { "time": "07:00", "days": [ "Sun", "Mon", "Tue", "Web", "Thu", "Fri", "Sat" ] } ] アラーム再生クラス  AlarmSpeakerクラスではアラーム再生処理と、眠気検知チェック処理を実行します。 alarmSpeaker.py """ alarmSleaker.py Summay: Alarm sleaker. """ import os import cv2 import wave import pyaudio import random import threading from detectionSleepiness import DetectionSleepiness class AlarmSpeaker: """ AlarmSpeaker. """ # Sound path. __SOUNDS_DIR = "./sounds" def __init__(self): """ Init constructor. """ self.__isRunning = False self.__speakerThreadObj = None self.__checkSleepinessThreadObj = None def __del__(self): """ Destructor. """ self.stopThread() def goOff(self): """ Go off the alarm. """ self.stopThread() self.startThread() def startThread(self): """ Start SpeakerThread and CheckSleepinessThread. """ self.__isRunning = True if self.__speakerThreadObj is None: self.__speakerThreadObj = threading.Thread(target=self.__speakerThread) self.__speakerThreadObj.start() if self.__checkSleepinessThreadObj is None: self.__checkSleepinessThreadObj = threading.Thread(target=self.__checkSleepinessThread) self.__checkSleepinessThreadObj.start() def stopThread(self): """ Stop SpeakerThread and CheckSleepinessThread. """ self.__isRunning = False if self.__speakerThreadObj is not None: self.__speakerThreadObj.join() self.__speakerThreadObj = None if self.__checkSleepinessThreadObj is not None: self.__checkSleepinessThreadObj.join() self.__checkSleepinessThreadObj = None def __checkSleepinessThread(self): """ Check sleepiness form the camera. """ infApp = DetectionSleepiness() camera = cv2.VideoCapture(0) while self.__isRunning: _, frame = camera.read() if infApp.isSleepy(frame) == False: self.__isRunning = False def __speakerThread(self): """ Continue to sound music until stopped status. """ sound = self.__SOUNDS_DIR + "/" + random.choice(os.listdir(self.__SOUNDS_DIR)) while self.__isRunning: wf = wave.open(sound, "r") audio = pyaudio.PyAudio() stream = audio.open(format=audio.get_format_from_width(wf.getsampwidth()), channels=wf.getnchannels(), rate=wf.getframerate(), output=True) data = wf.readframes(1024) while data != b'' and self.__isRunning: stream.write(data) data = wf.readframes(1024) stream.stop_stream() stream.close() audio.terminate() wf.close()  このクラスではアラーム再生スレッド(__speakerThread)と眠気チェックスレッド(__checkSleepinessThread)の2つのスレッドを動作します。__speakerThreadスレッドでは__SOUNDS_DIRディレクトリに格納されたアラームファイルの再生を__isRunningがFalseになるまで繰り返し再生を行います。__isRunningは__checkSleepinessThreadスレッドで目覚め状態を検知すると、Falseを設定します。つまり、目覚め状態になるまで、アラームを繰り返し再生続ける動作となります。 最後に  今回はカメラから目覚めを検知する目覚まし時計を作成しました。普通の目覚まし時計とは違い、物理スイッチでアラームを止めることが出来ないので、より起きやすい環境を作ることはできたと感じています。課題としては、現状は目だけで判定しているため、目を無理やり開けると目覚め状態として検知してしまうので、顔全体で判定するアルゴリズムを考える必要があります。  また、アラーム設定をjson形式のファイルに設定するようにしていますが、ファイルを編集するのは面倒なのでWebページから設定できるように改良しようと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ML-AgentsをMacbook M1(Apple Silicon)インストール時にエラー起きたときの対処法

Macbook M1 で先駆者の記事を参考にML-Agentsを導入しようとしたら、ライブラリインストール時にエラーが出ました。そのエラーにどんな対処したかの備忘録になります。 サンプル(3Dball)を動かすところまでしか試していません。 TL;DR grpcio, h5pyライブラリをcondaでインストール PyTorch 1.8.0をインストール 最終目的 ML-Agents Release 18のインストールを行う。 その後、ML-AgentsのサンプルScene(Ball)の学習済みモデルでの推論、学習を行う。 自分の環境 Macbook Air (M1, 2020) macOS Big Sur ver11.2.2 Python 3.8.x (miniforgeで導入 参考: https://zenn.dev/karaage0703/articles/f3254b14898b4d) ML-Agentインストール手順 基本的には公式ドキュメントに従っていた。 https://github.com/Unity-Technologies/ml-agents/blob/release_18_docs/docs/Installation.md エラー発生箇所 1 ML-Agents用のAnaconda仮想環境に、ml-agentsとml-agents-envsのインストールを実行したところエラー発生。 Advanced: Local Installation for Development If you intend to make modifications to mlagents or mlagents_envs, you should install the packages from the cloned repository rather than from PyPi. To do this, you will need to install mlagents and mlagents_envs separately. From the repository's root directory, run: pip install torch -f https://download.pytorch.org/whl/torch_stable.html pip install -e ./ml-agents-envs pip install -e ./ml-agents エラー文章は長文だったので省略します。grpcio、h5pyインストール時にエラーが発生しているようでした。 エラー対処法 1 エラーが発生したライブラリをcondaでインストールしました。 pip, condaを混同して使っています。環境壊れる可能性があるので、もっといいやり方あれば教えて下さい。 conda install grpcio h5py エラー発生箇所 2 エラー発生箇所 1と同様。 エラー内容は、 ERROR: Could not find a version that satisfies the requiremet torch<1.9.0,>=1.6.0(from mlagents)(from versions: 0.1.2, 0.1.2.post1, 0.1.2 post2, 1.9.0 ERROR: No matching distribution found for torch<1.9.0,>=1.6.0 エラー対処法 2 原因はPyTorch1.9.0をインストールしていたからでした。 対処法はPyTorch 1.8.0をインストールすることです。自分はwheelファイルからインストールしました。 謎の先人によってwheelファイルが作成されているので、以下からダウンロードして~/Downloadsに配置しましょう。 https://drive.google.com/file/d/1e-7R3tfyJqv0P4ijZOLDYOleAJ0JrGyJ/view その後、以下のコマンドで既存のPyTorchをアンイストールして、PyTorch 1.8.0をインストールしましょう。 pip uninstall torch pip install ~/Downloads/torch-1.8.0a0-cp38-cp38-macosx_11_0_arm64.whl 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Djangoでモデルを定義する(基礎の基礎2)

1 やること 今回は、前回行ったDjango初期設定+Helloworldで作った超基礎的なウェブアプリケーションに、データベースを構築していきたいと思います。まず、models.pyでデータベースのフォーマットを設定し、管理者モードでデータベースにサンプルデータを作成します。そして、そのデータを呼び出してテンプレートのHTMLファイルを使ってレンダリングし、表示させるところまでをやってみます。(以下の内容の利用・実行は自己責任でお願いします。) 2 モデルの設定(models.py) Djangoの公式レファレンスのModelの解説ページにあるサンプルコードを参考にしてModel(models.py)を作ってみます。この解説ページにモデル作成における必要なことは全て書かれていると思いますので、余裕があれば、よく読んでみてください。 models.py from django.db import models class Reporter(models.Model): full_name = models.CharField(max_length=70) def __str__(self): return self.full_name class Article(models.Model): pub_date = models.DateField() headline = models.CharField(max_length=200) content = models.TextField() reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE) def __str__(self): return self.headline 3 管理者の設定と、サンプルデータの作成 管理者サイトで操作できるように、todo/admin.pyを以下のように編集して、モデルを登録します。 admin.py from django.contrib import admin from .models import Reporter, Article admin.site.register(Reporter) admin.site.register(Article) Modelを設定したら、makemigrationとmigrateを実行します。 (virtual) firstapp % python3 manage.py makemigrations Migrations for 'todo': todo/migrations/0001_initial.py - Create model Reporter - Create model Article (virtual) firstapp % python3 manage.py migrate Operations to perform: Apply all migrations: admin, auth, contenttypes, sessions, todo Running migrations: Applying todo.0001_initial... OK 管理者を設定します。(createsuperuserコマンドで以下のように設定します。----のところは各自の環境によります。) (virtual) firstapp % python3 manage.py createsuperuser Username (leave blank to use '----'): Email address: ----- Password: Password (again): Superuser created successfully. Runserverをして127.0.0.1:8000/admin/にアクセスをします。管理者名、設定したパスワードでログインをすると、モデルが反映されているはずなので、サンプルデータを作ってみます。例えば、以下のようなデータを適当につくってSaveします。 4.サンプルデータを呼び出し、レンダリングして出力 ウェブサイトの見た目を作るプログラムは、views.pyに記述します。前回作成したプログラムにmodeltestという新しい関数を定義します。objectをすべて取得する場合には、object.all()を使います。(ここで特定のobjectを選択的に取り出したい場合には、object_pickup = Article.objects.get(headline='---')といった形で抽出することもできます。) views.py from django.http.response import HttpResponseNotAllowed from django.shortcuts import render from .models import Reporter, Article def hello(request): hw = 'Hello World!' return render(request, 'base.html', {'object':hw}) def modeltest(request): object_list = Article.objects.all() return render(request, 'modeltest.html', {'object_list':object_list}) modeltest.htmlを次のように編集します。forループがhtmlで使えるようになるのはウェブアプリケーションの醍醐味です。 modeltest.html object_list:{{object_list}} {% for item in object_list %} <li>item:{{item}}</li> <li>item.pub_date:{{item.pub_date}}</li> <li>item.headline:{{item.headline}}</li> <li>item.content:{{item.content}}</li> <li>item.reporter:{{item.reporter}} </li> {% endfor %} todo/urls.pyについて、modeltestにアクセスした時に、views.pyのmodeltest関数が呼び出されるよう、以下の通り編集します。 urls.py from django.urls import path from .views import hello, modeltest urlpatterns = [ path('hello/', hello, name='hello'), path('modeltest/', modeltest, name = 'modeltest'), ] これで準備が整いました! 127.0.0.1:8000/modeltest/にアクセスすると、以下のウェブサイトが表示されます。先ほど管理者サイトで作成したデータが呼び出されて表示されることが確認できます。 <QuerySet [<Article: テスト>]> item:テスト item.pub_date:July 25, 2021 item.headline:テスト item.content:これはテストです。 item.reporter:投稿者1
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

非線形でも相関を捉えられるMIC関数

本記事はQrunchに投稿していた記事の再掲になります。 そのため、本記事に類似して且つ詳しい記事がQiita上に存在するかもしれません。 悪しからず。 相関とは 一般的に相関と言われているのは、ピアソンの相関(以下、相関)。 相関は2つのデータの直線的な関連度合いを-1 ~ +1で表す。 相関とは 相関の強さ 以下のコードでは、一次関数に従い乱数を生成している。 グラフのプロットの通り、直線的な関係が見て取れる。 相関係数は0.96なので、かなり強い相関だといえる。 import numpy as np from matplotlib import pyplot as plt # 乱数生成 x = np.random.normal(0,1, 1000) noise = np.random.rand(1000) y = (x + noise) # グラフ描画 plt.scatter(x, y) plt.show() # 相関係数 print(np.corrcoef(x, y)) # 0.96... 相関のよくある勘違い 繰り返しだが、 相関は2つのデータの直線的な関連度合いを表す。 相関 = 2つのデータの関連度合いというのは間違い。 以下のコードでは、二次関数に従い乱数を生成している。 グラフのプロットの通り、直線的ではないが「xとyに関係があること」は見て取れる。 相関関係は0.06だった。 import numpy as np from matplotlib import pyplot as plt # 乱数生成 x = np.random.normal(0,1, 1000) noise = np.random.rand(1000) y = x**2 + noise # グラフ描画 plt.scatter(x, y) plt.show() # 相関係数 print(np.corrcoef(x, y)) # 0.06... 上述より、「相関係数が0に近い!このデータは関係性がないんだ!」と結論付けるのは危険ということがわかる。 データの関係性を表せる「相関係数」と2つの落とし穴 ちなみに、BMIと死亡リスクのグラフが同じような形らしい。 MIC相関 じゃあどうやって上記のような関連度合いを捉えるのか。 今回はMIC相関を使う。 MIC相関は21世紀に入ってから考案された手法で、 非線形(直線的な関係じゃない)データの関連度合いも数値化できる。 MIC相関はこちらがわかりやすい。 新しい相関係数"MIC"の解説 PythonでMIC相関 Pythonなら簡単にMIC相関が使える。 MIC関数を使うにはminepyが必要。 pip install minepy 上述と同様に、二次関数に従い乱数を生成している。 MIC相関は0.75だった。 このようにMIC相関では非線形(直線的な関係じゃない)データの関連度合いも数値化できる。 import numpy as np from matplotlib import pyplot as plt from minepy import MINE # 乱数生成 x = np.random.normal(0,1, 1000) noise = np.random.rand(1000) y = x**2 + noise # グラフ描画 plt.scatter(x, y) plt.show() # MIC相関 mine = MINE() mine.compute_score(x, y) print(mine.mic()) # 0.75... あとがき MIC相関は手法の特性上ノイズに弱い。 非線形でも関連性を捉えられるが、sin波のように周期的なデータには弱い。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PyInstallerによるPythonスクリプトのexe化とエラー対処方法まとめ

はじめに  この記事では、PythonモジュールのひとつであるPyInstallerを用いたPythonスクリプトのexe化方法および各種エラー対処方法について説明します。PyInstallerでexe化することで、Pythonをインストールしていない環境においてもPythonスクリプトを実行させることができるようになります。業務においてちょっとしたツールを作成しチームメンバーに配布したり、Tkinterと組み合わせてGUIを実装すれば、スタンドアロンで動くデスクトップアプリケーション(前回記事を参考)を作成することも可能です。 目次 はじめに 作成の動機 PyInstallerとは exe化の一連の流れ 仮想環境作成 PyInstaller実行 exeファイルの軽量化 各種エラー対処方法 その他 注意点 最後に 作成の動機  PyInstallerに関する記事についてはQiita内やWEB上を探せばいくつか見つけることができますが、exe化の一連の流れや注意点、作成したexeファイルの軽量化方法についてひとつの記事にまとめているものはなく、過去PyInstallerの使い方を調べる際に点在した情報を探すのにとても苦労したことから、今回PyInstallerの使用方法をまとめた記事を作成することにしました。 また、以前書いた記事「Python未導入環境においてPandasGUIとpandas-profilingを使用可能なEDAツール『Pandas Anywhere』を作ってみた」ではPandasGUI、pandas-profillingモジュールを含むスクリプトのexe化に取り組みましたが、多くのエラーに遭遇し、解消に苦労したので、この際に出てきたエラーとその対処方法についても併せて述べたいと思います。 PyInstallerとは Pythonスクリプトをexe化するためのPythonモジュール。ver4.3ではPython3.9までがサポートされています。 実行時のオプション指定で1つのexeファイルにまとめたり、exeファイル実行時にコンソール画面を非表示にすることができる(詳細は後述)。 スクリプトをexe化するモジュールとしては、PyInstaller以外にも「cx_Freeze」がある。PyInstallerとの違いは、PyInstallerはオプション指定で1つのexeファイルにまとめられるが、cx_Freezeでは複数ファイルに分かれた形でのexe化となる。exeファイルの起動速度についてはcx_Freezeのほうが速い模様。 exe化の一連の流れ 仮想環境の作成 PyInstallerの実行 exeファイルの軽量化 エラー対応 ※ 3.以降は必要に応じて実行 1.仮想環境作成  PyInstallerを用いたexe化の初期手順として必ず仮想環境を作成して、仮想環境上で行います。PyInstallerでexe化する際は、スクリプトに記載されているモジュールがexeファイルに同封されるわけではなく、開発環境上に存在しているすべてのモジュールが同封されます。つまり、exe化するスクリプト上ではpandasやnumpyしか使用していないとしても、例えば開発環境上にTensorFlowやPyTorchがインストールされているのであればこれらのモジュールも同封されてしまいます(その結果、ものすごい大容量のexeファイルができあがります)。そのため、exe化する際は必ず仮想環境上で実行するようにして下さい。 ※作者実行環境 OS: Windows10 Python: Python3.7.3 Pyinstaller: ver4.2 PCユーザ名: username 例で「testvenv」という名前の仮想環境を作成 console python -m venv testvenv 作成した仮想環境の起動 console C:\Users\username\testvenv\Scripts\activate # Windows10環境 # PCユーザ名: username pipの最新化 console pip install -U pip Pythonスクリプト上で使用するモジュールのインポート ※ファイル容量を少なくするために、exe化するスクリプトで使用しない余計なモジュールはインストールしないこと。 console pip install pyinstaller # pip installの一例 2.PyInstaller実行  Desktop 上の「test」フォルダ内に作成した「main.py」というスクリプトをexe化する場合 console cd C:\Users\username\Desktop\test pyinstaller main.py ※実行環境によっては「PyInstaller」のように「P」と「I」を大文字で指定しないと上手く実行できない場合があるようです。 上記操作の実行によりtestフォルダ内に以下の通りフォルダ、ファイルが作成されます。 ディレクトリ構成 test  ├ main.py … スクリプトファイル(自身で用意したファイル)  ├ main.spec … PyInstaller実行後に作成される中間ファイル、エラー発生時等にPyInstaller実行時の設定をここに記述  ├ dist … ここにexeファイルや関連ファイルが格納されたフォルダが作成、配布時はこのフォルダごと配布するイメージ  └ build … このフォルダの中身を触ることは特にありません 以下のようにdistフォルダ内にexeファイルと関連ファイルが作成されます。 オプションの指定 --onefile onefileオプションを指定することで、スクリプト実行に関連するファイルを1つのexeファイルにまとめてくれます。私がツールを配布する際は基本的にこのオプションを指定しています。 console pyinstaller main.py --onefile 以下のようにdistフォルダ内に1つのexeファイルが作成されます。 --noconsole noconsoleオプションを指定することで、exeファイル実行時に表示されるコンソール画面を非表示にできます。ツール配布時に余計な画面を表示させたくない場合には指定すると良いですが、コンソール画面に表示されるエラー内容が見れなくなるのでデバッグ中は指定しないほうが良いです。 console pyinstaller main.py --noconsole 3.exeファイルの軽量化  仮にスクリプト内でpandas、numpyしか使用しない簡単なデータ集計ツールを作ったとしても、作成されたexeファイルは300MB程度にはなってしまうと思います。原因としてはpandasやnumpyモジュール内に含まれているIntel MKLというInter CPUに特化した高速線形演算ライブラリが原因。これを除外することでexeファイルの容量を30MB程度にすることができます。 specファイルに以下の破線の範囲を追記します。 main.spec # -*- mode: python ; coding: utf-8 -*- block_cipher = None a = Analysis(['main.py'], pathex=['C:\\Users\\username\\Desktop\\test'], binaries=[], datas=[], hiddenimports=[], hookspath=[], hooksconfig={}, runtime_hooks=[], excludes=[], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False) pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) #---------------追加ここから--------------- Key = ['mkl'] def remove_from_list(input, keys): outlist = [] for item in input: name, _, _ = item flag = 0 for key_word in keys: if name.find(key_word) > -1: flag = 1 if flag != 1: outlist.append(item) return outlist a.binaries = remove_from_list(a.binaries, Key) #---------------追加ここまで--------------- exe = EXE(pyz, a.scripts, [], exclude_binaries=True, name='main', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, console=True, disable_windowed_traceback=False, target_arch=None, codesign_identity=None, entitlements_file=None ) coll = COLLECT(exe, a.binaries, a.zipfiles, a.datas, strip=False, upx=True, upx_exclude=[], name='main') ★追記後にbuild、distフォルダを一度削除し、以下の通りPyInstallerを実行するとdistフォルダ内に新しくexeファイルが作成されます(pyファイルではなく、specファイルを指定していることに注意)。 console pyinstaller main.spec --onefile MKLを除外したことによりexeファイルが軽量化されていることが確認できるはずです。 4.各種エラー対処方法 ①ModuleNotFoundError ModuleNotFoundError: No module named ''pandas_profiling.describe'' このエラーが出た場合は、エラーに記載のモジュールが上手くexeファイルに同封できていません。そのため、specファイル内の「hiddenimports」の項に以下の通り、モジュールインポートが上手くできていないことを明示的に記述してあげます。 hiddenimports=['pandas_profiling.describe'] 記述後に、上述の★の操作でPyInstallerを再度実行すると新しくexeファイルが作成されます。 このexeファイルを実行して、再度別のModuleNotFoundErrorが出る場合は、先ほどのhiddenimportsの項目にカンマ区切りでエラーに該当するモジュールを付け足していって下さい。 ②FileNotFoundError FileNotFoundError: [Errno 2] No such file or directory: 'C:\Users\username\AppData\Local\Temp\_MEI103442\wordcloud\ipaexg.ttf' このエラーが出た場合は、エラーに記載のファイルが上手くexeファイルに同封できていません。そのため、specファイル内の「datas」の項に以下の通り、ファイルインポートが上手くできていないことを明示的に記述してあげます。 datas = [('C:\\Users\\username\\testvenv\\lib\\sitepackages\\wordcloud\\ipaexg.ttf','\\wordcloud\\')] 記述後に、上述の★の操作でPyInstallerを再度実行すると新しくexeファイルが作成されます。 このexeファイルを実行して、再度別のFileNotFoundErrorが出る場合は、先ほどのdatasの項目にカンマ区切りでエラーに該当するファイルを付け足していって下さい。 ③Recursion error : maximum recursion depth exceeded Recursion error : maximum recursion depth exceeded このエラーは、関数内で再帰のしすぎでPythonのデフォルト再帰回数の1000回を超えてしまう際に発生します。このエラーは、スクリプト内で再帰関数を使っていない場合にも発生するため、PyInstaller内で再帰関数が使われていると考えられます。対処方法としては、スクリプト内に以下の記述を追加し、許容する再帰回数上限を1000回から上げます。 import sys sys.setrecursionlimit(10000) # 再帰回数の上限を10000回に設定 エラーについては①と②がほとんどだと思われるので、この2つのエラーの対処方法を押さえておけばまずは大丈夫だと思います。 その他 以前書いた記事「Python未導入環境においてPandasGUIとpandas-profilingを使用可能なEDAツール『Pandas Anywhere』を作ってみた」では、ModuleNotFoundErrorが100回以上発生したため、ModuleNotFoundErrorが発生する特定モジュール内のサブモジュール名をすべて取得するスクリプトを作成して対応しました(エラー発生に切りがなかったので取得したすべてのサブモジュール名をhiddenimportsに記述。具体的にはPlotlyモジュール内のlayout配下のサブモジュールがすべてModuleNotFoundErrorになりました)。 参考に、サブモジュール名を取得するスクリプトを以下に載せておきます。 ※plotly.validators配下のlayoutフォルダ内のサブモジュール名をすべて取得する場合の例で、スクリプトと同一ディレクトリ内にlayoutフォルダを丸ごとコピーして実行すると結果がprint出力されます。 import os sbfolder = [] for fd_path, sb_folder, sb_file in os.walk('layout'): # os.walk()の括弧内は格納するモジュールのフォルダ名を記載 for fol in sb_folder: path = fd_path + '\\' + fol path2 = 'plotly.validators.' + path # 必要に応じて書き換え path2 = path2.replace("\\" , ".") if 'pycache' not in path2: sbfolder.append(path2) print(sbfolder) # 以下のprint結果を、specファイルのhiddenimportsに記入 # ['plotly.validators.layout.activeshape', 'plotly.validators.layout.angularaxis', # ... # 'plotly.validators.layout.yaxis.title', 'plotly.validators.layout.yaxis.title.font'] 注意点 以下はPyInstallerを用いて作成したexeファイルの使用時の注意点です。 exeファイルを実行できるOS環境は、PyInstallerを実行したOS環境のみ 例えば、Window10 64bit環境で作成したexeファイルを実行できるのはWindows10 64bit環境のみです。 起動に時間がかかる 実行するPCのスペックやexeファイルの中身にも依りますが、exeファイルを起動するのに簡易なもので30秒、重いもので1分以上かかることがあります。 参考 【Python】TIPS:pyinstallerの軽量化【exe化】 pyinstaller によるexe化のエラーメッセージと対処方法 最後に 以上、PyInstallerの使用方法になります。他にもいろいろとエラーはあったので、思い出し次第、追記していきたいと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Pythonistaで綺麗なハート?をプロット

はじめに ふと美しい数式をプロットしたくなり、美しい数式を眺めていたら、綺麗なハート型になる数式を見つけた。 その数式をPythonでプロットしてみることにした。 なんとなくスマホですっとハートを出せるようにしたくなったため、Pythonistaで動作するように作成した。 実装方針 元となる数式について 描きたい数式: $$(x^2 + y^2 - 1)^3 = x^2 y^3$$ これを$y$について解くと $$y = \frac{1}{2}(x^\frac{2}{3} \pm \sqrt{x^\frac{4}{3} + 4 (1 - x^2)})$$ 実数の平方根は正であるから、$x^\frac{4}{3} + 4 (1 - x^2) \ge 0$である。 これを解くと $$-1.1390 \lessapprox x \lessapprox 1.1390$$ 問題:Pythonistaで立方根を求めるnumpy.cbrtが使えない! numpy.cbrtがimportできない場合に、cbrtの代わりとなるものを作りたい。 powで立方根自体は求められるが、引数が負数になるとエラーとなってしまう。 つまり、$x$が正($x\ge0$)のとき pow(x, 1/3) を返したい。また、$x$が負($x<0$)のとき -pow(-x, 1/3) を返したい。 numpy.ndarrayでは、x[条件式]で条件式を満たすものを抽出することができる。 すなわち、$x\ge0$のものを抽出する場合は以下のようになる。 x[x >= 0] 以上のことをまとめると、cbrtは以下のように書くことができる。 cbrt = lambda x: np.append(-pow(-x[x < 0], 1/3), pow(x[x >= 0], 1/3)) コード """ハート型をプロットする""" import matplotlib.pyplot as plt import numpy as np # Pythonistaのnumpyではcbrtが使えないため try: from numpy import cbrt except ImportError: cbrt = lambda x: np.append(-pow(-x[x < 0], 1/3), pow(x[x >= 0], 1/3)) def numpy_heart(): """ハート型をプロットする 数式:(x^2 + y^2 - 1)^3 = x^2 * y^3 yについて解いた数式:y = 1/2 * (x^(2/3) +- sqrt(x^(4/3) + 4 * (1 - x^2))) 実数の平方根は正であるから、 x^(4/3) + 4 * (1 - x^2) = 0の解が, x ~ +-1.1390であるため、 xが+-1.1390の範囲を計算し、プロットする。 """ x = np.arange(-1.1390, 1.1391, 0.0001) y_sqrt = np.sqrt(x * cbrt(x) + 4 * (1 - np.power(x, 2))) y_positive = (np.power(cbrt(x), 2) + y_sqrt) / 2 y_negative = (np.power(cbrt(x), 2) - y_sqrt) / 2 plt.plot(x, y_positive, color="pink") plt.plot(x, y_negative, color="pink") plt.show() def main(): numpy_heart() if __name__ == '__main__': main() 実行結果 実行結果のハート型のプロット画像 参考文献 Heart Curve -- from Wolfram MathWorld
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

オフライン環境下でAnaconda仮想環境を構築する方法

背景 オフライン環境下のマシンにパッケージ盛り盛りのPython環境を整えたのでそのメモ。 本記事ではAnacondaを使用して環境構築を行います。 ちなみに、すでにいくつかの記事でオフライン環境下で仮想環境を構築する方法や、パッケージをインストールする方法が紹介されています。 例えば、 - オフライン環境下にあるPCにAnaconda仮想環境を構築するお話 - WindowsオフラインパソコンにcondaでPython環境構築 - pip installをオフラインで行う これらの記事に従うと仮想環境の作成まではスムーズにいったのですが、パッケージのインストールで躓きました。 まず、conda installを使う場合は、必要なソースファイル(.conda, .tar.bz2)を.../anaconda3/pkgs/下から探すの面倒です。pip install では単純に目的のソースファイル(.whl)のみを持ってきても、うまくいかない場合があります。この原因はパッケージ間に依存関係があるためです。例えば、OpenCVを利用するにはNumPyが必要なので、OpenCVのwhlファイルのみ準備しても、インストールに失敗します。一応、エラー理由を見て、どのパッケージが足りていないかを確認し、必要なwhlファイルを準備する。これを繰り返せばオフライン環境下で所望のパッケージのインストールも可能ですが、あまりに面倒です。 本記事では、この面倒な手続きをすっ飛ばす簡単な方法を紹介します。 必要なもの オフライン環境下のマシン(以下、オフラインマシン) オフラインマシンと同じOSを搭載したオンライン環境のマシン(以下、オンラインマシン) 同じOSを用意するのはビルドされたパッケージがOSに依存している場合があるためです。また、事前に両マシンには同一バージョンのAnacondaをインストールしてください。 方法 オンラインマシンで環境構築を行い、オフラインマシンに移植(コピペ)します。 オンラインマシン内でconda仮想環境を作成 必要なパッケージをインストール 仮想環境のフォルダごとオフラインマシンに配置 conda仮想環境の作り方などは他記事を参照ください。 所望の環境が作成したら、ターミナルでconda info -eと叩き、仮想環境の実体がどこにあるか確認します。Macの場合デフォルトでは/opt/anaconda3/envs/{環境名}にあるはずです。 あとはこの{環境名}のフォルダをコピーして、オフラインマシンの.../anaconda3/envs/下に置くだけ。 これでオンラインマシンで作成した環境をオフラインマシンで使用できます。 解説 オンラインマシンで用意した環境をオフラインマシンに移植(コピペ)しました。 間違いなどありましたらご指摘お願いします。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VSCodeでPythonの仮想環境に切り替える

背景 VSCodeを立ち上げて仮想環境を実行する度にPowerShell スクリプトの実行ポリシー変更するのが面倒 やった事 F1 キーでコマンドパレットを表示。 "Open Settings(JSON)"を入力してsettings.jsonを開いて下記を追加 Windows "terminal.integrated.env.windows": { "PSExecutionPolicyPreference": "RemoteSigned" } あとは、PowerShell で仮想環境のactivate 用スクリプトを実行すればよい。 例)./venv/Scripts/Activate.ps1
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Bosch BME280をRasPiにつなぐときの設定

はじめに おじさんは以前にBME280をESP32やらRasPiにつないでクラウドにデータをupload していました。今回、新たにセンサーを購入し、クラウドも刷新して作ろうと思ったのですが、humidity が0と読めず、悩みに悩みました。結果、購入したものがBMP280でhumidity を出力しない、似て非なるものだった、という落ちでした。(悲しい) 購入したのははるか昔なのだが、「安いので5個まとめ買い」をしてました。多分amazon で BME280と書かれていたのではと疑っています。(←自分で確認してみるか。。。) せっかくなので、いろいろ見直した時の内容をメモしておきます。 Raspberry Piの I2Cの設定 配線の確認 I2Cで使うので、こんな感じ。 I2Cの設定確認 raspi-config でI2Cを有効にし、i2ctools をインストールします。 $ lsmod | grep i2c i2c_bcm2835 16384 1 i2c_dev 16384 2 $ i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- 76 -- $ cat /etc/modules | grep i2c i2c-dev $ cat /boot/config.txt | grep i2c dtparam=i2c_arm=on I2Cのbaudrate が dmesg で見れるらしいのだが、おじさんはできなかった。 I2Cのbaudrate を変えられるようなので変えてみた。この記事を参考に。 dtparam=i2c_baudrate=50000 を最終行に追加しました。50kということかな。 配線 当初は下記の記事を読み、pull-up 抵抗が必要かもと思いました。RasPi様は 内蔵している聞いていたので何もしていません。 おじさんはオシロ使えないので。 BME280と BMP280の区別 humidity が読めないのでわかる、というのは後付けの知識。 IDのregister を読むと明白です。以下は仕様書。 0x0Dを読んでみる。 from smbus2 import SMBus bus_number = 1 bus = SMBus(bus_number) i2c_address = 0x76 bus.write_byte_data(i2c_address, 0xE0, 0xB6) print("chip ID: ", hex(bus.read_byte_data(i2c_address, 0xD0)) ) 哀しいことに私のところでの実行結果は chip ID: 0x58 だった。 初期化の処理 初期化で実行するのは 測定サイクルとオーバーサンプリングの設定 configuration parameter の読み込みです 測定サイクルとOversampling の設定 ODR (output data rate)は測定時間と待機時間から計算できる。例えば normal mode なら 1000[ms] / ( 11.5 + 62.5) [ms] = 13.51 [Hz] その他の特性値 IIR filter の時定数、消費電流は ODRから計算できる。 config パラメータの読み込み 0x88から0xE7まで読みます。ここら辺はたくさんの実装例が転がっているので省略。 ソースコード python でこんなのもあった。 まとめ BME280 (Bosch)だと思ってhumidityを読もうとしたが、実はBMP280で読めなかった。確認するにはレジスタ値で chip ID を確認すればよい。 (2021/07/25)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Databricksにて外部Hive Metastoreを構築する方法の検証

注意事項 調査中ですが、意見を募集したいため記事を投稿します。 記事内容を更新する可能性があります。 概要 Databricksにて外部Hive Metastoreを構築する方法の検証を整理します。 下記の表が外部Hive Metastoreを構築する方法の概要、それぞれの検証結果の詳細を後述します。 # 方法 実施可否 問題・課題 1 Databricksのドキュメント通りにSpark Configにより構築する方法 〇 spark.conf.getにより接続情報を取得できてしまうこと。 2 Hive Metastoreへの接続情報ファイル(hive-site.xml)を置き換える方法 × ファイル置き換え前のデータベースに接続してしまうこと。 3 Hive Metastoreへの接続情報ファイルに対する参照パスの環境変数(CONF_HIVE_CONF_DIR)を置き換える方法 × 外部メタストアデータベースへ接続できず、データベースを作成しても永続化されないこと。 Databricksではデフォルトで内部のHive Metastoreデータベースを参照する仕様であり、Azure Databricksではリージョンごとに共通のAzure Database for Mysqlを利用するようになっているようです。Hive Metastoreデータベースへの接続情報の取得方法としては下記のドキュメントで紹介されております。 引用元:Azure Purview で Hive メタストア データベースを登録してスキャンを設定する - Azure Purview | Microsoft Docs 参考になる情報としてDatabricksのドキュメントがありますが、AWS版DatabricksとAzure Databricksでは記載内容が異なり、どちらも参考になります。 外部Apache Hiveメタストア - Azure Databricks - Workspace | Microsoft Docs External Apache Hive metastore | Databricks on AWS SparkにおけるHive Metastoreの動作を概要を利用するには、GMOインターネットグループ様のブログ記事がとても参考になります。 Hadoop上でSpark+Delta Lakeを検証してみた~続き | GMOインターネットグループ 次世代システム研究室 1. Databricksのドキュメント通りにSpark Configにより構築する方法 構築方法 下記の記事に記載しております。 Databricksにおける外部Hive MetastoreをMySQL(Azure Database for MySQL)にてローカルモードでSpark Configにて構築する方法 - Qiita Databricksにおける外部Hive MetastoreをAzure SQL DatabaseにてローカルモードでSpark Configにて構築する方法 - Qiita 課題 課題1-1. spark.conf.getにより接続情報を取得できてしまうこと Databricksシークレットに格納することで値を表示しないようにできてしまうが、jdbc経由でHive Metastoreデータベースに接続できてしまうという課題がある。 2. Hive Metastoreへの接続情報ファイル(hive-site.xml)を置き換える方法 構築方法 下記のコードを実行してhive-site.xmlを置き換えます。 contents = """ <configuration> <property> <name>javax.jdo.option.ConnectionURL</name> <value>jdbc:sqlserver://{databaseへの接続情報}</value> <description>JDBC connect string for a JDBC metastore</description> </property> <property> <name>javax.jdo.option.ConnectionDriverName</name> <value>com.microsoft.sqlserver.jdbc.SQLServerDriver</value> <description>Driver class name for a JDBC metastore</description> </property> <property> <name>javax.jdo.option.ConnectionUserName</name> <value>{ユーザー}</value> <description>Username to use against metastore database</description> </property> <property> <name>javax.jdo.option.ConnectionPassword</name> <value>{パスワード}</value> <description>Password to use against metastore database</description> </property> <!-- If the following two properties are not set correctly, the metastore will attempt to initialize its schema upon startup --> <property> <name>datanucleus.schema.autoCreateAll</name> <value>false</value> </property> <property> <name>datanucleus.autoCreateSchema</name> <value>false</value> </property> <property> <name>datanucleus.fixedDatastore</name> <value>true</value> </property> <property> <name>datanucleus.connectionPool.minPoolSize</name> <value>0</value> </property> <property> <name>datanucleus.connectionPool.initialPoolSize</name> <value>0</value> </property> <property> <name>datanucleus.connectionPool.maxPoolSize</name> <value>1</value> </property> <property> <name>hive.stats.autogather</name> <value>false</value> </property> <property> <name>mapred.reduce.tasks</name> <value>100</value> </property> <!-- To mitigate the problem of PROD-4498 and per HIVE-7140, we need to bump the timeout. Since the default value of this property used by Impala is 3600 seconds, we will use this value for actual deployment (http://www.cloudera.com/content/cloudera/en/documentation/core/latest/topics/cm_props_cdh530_impala.html). --> <property> <name>hive.metastore.client.socket.timeout</name> <value>3600</value> </property> <property> <name>hadoop.tmp.dir</name> <value>/local_disk0/tmp</value> </property> <property> <name>hive.metastore.client.connect.retry.delay</name> <value>10</value> </property> <property> <name>hive.metastore.failure.retries</name> <value>30</value> </property> </configuration> """ dbutils.fs.put( file = "file:/databricks/hive/conf/hive-site.xml", contents = contents, overwrite = True, ) 課題 課題2-1. ファイル置き換え前のデータベースに接続してしまうこと ファイルを置き換えてもデータベースは切り替わらず、クラスターを再起動するとhive-site.xmlが初期化されてしまいます。 hive-site.xml置き換え前のデータベース hive-site.xml置き換え後のデータベース 3. Hive Metastoreへの接続情報ファイルに対する参照パスの環境変数(CONF_HIVE_CONF_DIR)を置き換える方法 構築方法 下記のコードにより、dbfs上にhive-site.xmlを配置します。。 contents = """ <configuration> <property> <name>javax.jdo.option.ConnectionURL</name> <value>jdbc:sqlserver://{databaseへの接続情報}</value> <description>JDBC connect string for a JDBC metastore</description> </property> <property> <name>javax.jdo.option.ConnectionDriverName</name> <value>com.microsoft.sqlserver.jdbc.SQLServerDriver</value> <description>Driver class name for a JDBC metastore</description> </property> <property> <name>javax.jdo.option.ConnectionUserName</name> <value>{ユーザーID}</value> <description>Username to use against metastore database</description> </property> <property> <name>javax.jdo.option.ConnectionPassword</name> <value>{パスワード}</value> <description>Password to use against metastore database</description> </property> <!-- If the following two properties are not set correctly, the metastore will attempt to initialize its schema upon startup --> <property> <name>datanucleus.schema.autoCreateAll</name> <value>false</value> </property> <property> <name>datanucleus.autoCreateSchema</name> <value>false</value> </property> <property> <name>datanucleus.fixedDatastore</name> <value>true</value> </property> <property> <name>datanucleus.connectionPool.minPoolSize</name> <value>0</value> </property> <property> <name>datanucleus.connectionPool.initialPoolSize</name> <value>0</value> </property> <property> <name>datanucleus.connectionPool.maxPoolSize</name> <value>1</value> </property> <property> <name>hive.stats.autogather</name> <value>false</value> </property> <property> <name>mapred.reduce.tasks</name> <value>100</value> </property> <!-- To mitigate the problem of PROD-4498 and per HIVE-7140, we need to bump the timeout. Since the default value of this property used by Impala is 3600 seconds, we will use this value for actual deployment (http://www.cloudera.com/content/cloudera/en/documentation/core/latest/topics/cm_props_cdh530_impala.html). --> <property> <name>hive.metastore.client.socket.timeout</name> <value>3600</value> </property> <property> <name>hadoop.tmp.dir</name> <value>/local_disk0/tmp</value> </property> <property> <name>hive.metastore.client.connect.retry.delay</name> <value>10</value> </property> <property> <name>hive.metastore.failure.retries</name> <value>30</value> </property> </configuration> """ dbutils.fs.put( file = "dbfs:/FileStore/hive/conf/hive-site.xml", contents = contents, overwrite = True, ) Environment Variablesにて下記の値を設定。 CONF_HIVE_CONF_DIR=/dbfs/FileStore/hive/conf/hive-site.xml 課題 課題3-1. 外部メタストアデータベースへ接続できず、データベースを作成しても永続化されないこと データベース作成することは可能ですが、Hive Metastoreデータベースにもデータが書き込まれておりませんでした。 クラスターを再起動すると、データベースが初期化されてしまいます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

pyautoguiでChromeを立ち上げて検索を行う

概要 使った事がないpyautoguiを試しに使ってみるために、実用性は皆無なコードを作成して遊んでみる 仕様 ・タスクバーにあるGoogle Chromeをクリックして、ブラウザを立ち上げた後に「オリンピック」という文字を検索窓に入力して検索する。 ・Google Chromeはタスクバーにピン止めしてある前提 ・マルチディスプレイには非対応 ・Google Chromeのアイコンの場所、検索窓の場所は画像認識(保存画像とディスプレイ上の画像の比較)で行う 事前準備 pyautoguiをインストール pip install pyautogui 画像処理ライブラリPillowをインストール pip install Pillow OpenCVをインストール pip install opencv-python pip install opencv-contrib-python 画像認識用の画像を事前に準備する。 Windowsの場合は、[Windows]+[Shift]+[S]キーで画像を切り取って保存するのがおすすめです。 今回は以下の2つの画像を準備しています。 chrome.png search.png コード #使用するモジュールをインポート import pyautogui as pa import pyperclip import time #タスクバーにあるGoogle Chromeを画像認識で座標取得 position = pa.locateOnScreen("chrome.png", confidence=0.8)#confidenceが低いほど曖昧マッチング #画像認識した座標をダブルクリック pa.doubleClick(position) #ブラウザが開ききるまで time.sleep(1) #ブラウザ画面を最大化しとかないと何故かうまくいかなかったので、画面を最大化しておく pa.hotkey("win", "up") #ブラウザの検索窓を画像認識で取得 search_pos = pa.locateOnScreen("search.PNG", confidence=0.1) # 特徴的な画像ではないのでconfidenceを低くしないとうまくマッチングしない pa.click(search_pos) #「オリンピック」という文字列を検索窓に入力 pyperclip.copy("オリンピック") pa.hotkey("ctrl", "v") #エンターキーを押して検索を実行 pa.press("enter")
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

brew doctorをするとコマンドツールが古いとWARNINGが出た時の対処

状況と原因 ・brew doctorの照会をすると以下のWARNINGがが続出した。(当然のことながら、brewのupdateとupgradeは行った上でのこと。) ・ brew configでシステム構成を確認したところ、原因はCLT と Xcodeのバージョンが一致していないことらしいので、doctorの指示に従って  ‘https://developer.apple.com/download/more/。’ から Xcode12.5用のコマンドラインツールをダウンロードしてみたところ表示が消えた。 ちなみに、私の場合これを行う前にdoctorの指示にある softwareupdate --all --install —force 並びに sudo rm -rf / Library / Developer / CommandLineTools sudo xcode-select —install を先に行ったが、softwareupdateでは変化なく、ターミナルからのsudo rm -rf行ったところ時間がかかった挙句、システム復元が必要になった。 「WARNINGの表示の一部」 hogehogeiMac ~ % brew doctor Warning: Your Command Line Tools are too outdated. Update them from Software Update in System Preferences or run: softwareupdate --all --install --force If that doesn't show you any updates, run: sudo rm -rf /Library/Developer/CommandLineTools sudo xcode-select --install Alternatively, manually download them from: https://developer.apple.com/download/more/. You should download the Command Line Tools for Xcode 12.5 ※ちなみに"hogehoge"は私の名前を隠しています。 これをgoogle翻訳すると 警告:コマンドラインツールが古すぎます。 システム環境設定のソフトウェアアップデートから更新するか、以下を実行します。 softwareupdate --all --install --force それでも更新が表示されない場合は、次を実行します。 sudo rm -rf / Library / Developer / CommandLineTools sudo xcode-select --install または、次の場所から手動でダウンロードします。 https://developer.apple.com/download/more/。 Xcode12.5用のコマンドラインツールをダウンロードする必要があります。(Google翻訳) という意味らしい。 この他に後2件以下のWARNINGが表示された。 WARNING: A newer Command Line Tools release is available. (警告:新しいコマンドラインツールリリースが利用可能です。) WARNING: Your Command Line Tools (CLT) does not support macOS 11. (警告:コマンドラインツール(CLT)はmacOS11をサポートしていません。古くなっているか、変更されています)。 対処 ①brew configでシステム構成を確認 hogehogeiMac ~ % brew config HOMEBREW_VERSION: 3.2.3 ORIGIN: https://github.com/Homebrew/brew 〜〜省略〜〜 macOS: 11.5-x86_64 CLT: 11.3.0.32.62 <—Xcodeのバージョンとアンマッチの状態になっている Xcode: 12.5.1 ②下記HPへappleIDでサインインして、Xcodeと同じバージョンのコマンドラインツールをインストール(今回は:Command Line Tools for Xcode 12.5.1.dmg を選択してインストールした) https://developer.apple.com/download/more/。 (WARNINGの中で指示あり) ③ダウンロードしたコマンドラインツールのdmgを解凍後インストール 確認 brew configを実施してCLTとXcodeが一致していることを確認 hogehogeiMac ~ % brew config HOMEBREW_VERSION: 3.2.3 ORIGIN: https://github.com/Homebrew/brew 〜〜省略〜〜 macOS: 11.5-x86_64 CLT: 12.5.1.0.1.1623191612 <—一致した Xcode: 12.5.1 brew doctorを実施してみるとwarningが消えていた。 hogehogeiMac ~ % brew doctor Your system is ready to brew. システムを作成する準備ができました(google翻訳) 私は、この方法で正常に戻りましたが、飽くまで自己責任の下でお願いします。 参考にしたHP: https://code-graffiti.com/big-sur-and-homebrew-warning/ MacをBig SurにするとHomebrewでCTLについてのWarningが出ることへの対処法
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PythonでPLINKの主成分分析結果を可視化する方法

PLINKの---pcaコマンドで主成分分析を実施すると、 1.output.eigenvec 2.output.eigenval という2つのファイルが出力されます。 今回はこれらの2つのファイルを使用して、主成分分析の結果を可視化します。 ①Pythonで必要なライブラリをインポート import matplotlib.pyplot as plt import seaborn as sns import pandas as pd import japanize_matplotlib ②データの読み込み pandasのread_csvで、2ファイルを読み込みます。 .eigenvalの値から、PC1とPC2がどれだけの割合を説明できるのかを計算します。 ついでに、今回の主成分分析で使用したSNP数も.mapファイルから計算しておきます。 #データの読み込み df = pd.read_csv('output.eigenvec', sep=' ', header=None) #PC1とPC2の説明量を計算する PC = pd.read_csv('output.eigenval', sep=' ', header=None) su = PC[0].sum() p1 = PC.iloc[0, 0] PC1 = p1 / su * 100 p2 = PC.iloc[1, 0] PC2 = p2 / su * 100 #SNP数を計算する ma = pd.read_csv('output.map', sep=' ', header=None) snp = len(ma) ③PCAプロットの作成 先ほど計算した、SNP数や説明量をグラフに反映させました。 sns.set(font='Yu Gothic', context="talk", style='ticks') plt.figure(figsize=(12,8)) sns.scatterplot(x=2, y=3, data=df, s=100) plt.title("PCA Plot【%i SNPs】" %snp, fontweight="bold") plt.xlabel('PC1 (%i %)' %PC1) plt.ylabel('PC2 (%i %)' %PC2) plt.savefig('Output.png') #PNGで画像を保存 集団が複数ある場合などは、sns.scatterplotのhueで色分けも行えます。 全体 import matplotlib.pyplot as plt import seaborn as sns import pandas as pd import japanize_matplotlib #データの読み込み df = pd.read_csv('output.eigenvec', sep=' ', header=None) #PC1とPC2の説明量を計算する PC = pd.read_csv('output.eigenval', sep=' ', header=None) su = PC[0].sum() p1 = PC.iloc[0, 0] PC1 = p1 / su * 100 p2 = PC.iloc[1, 0] PC2 = p2 / su * 100 #SNP数を計算する ma = pd.read_csv('output.map', sep=' ', header=None) snp = len(ma) sns.set(font='Yu Gothic', context="talk", style='ticks') plt.figure(figsize=(12,8)) sns.scatterplot(x=2, y=3, data=df, s=100) plt.title("PCA Plot【%i SNPs】" %snp, fontweight="bold") plt.xlabel('PC1 (%i %)' %PC1) plt.ylabel('PC2 (%i %)' %PC2) plt.savefig('Output.png') #PNGで画像を保存 以上、PLINKの主成分分析の結果からPCAプロットを作成する方法でした。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LINEブロックチェーン チュートリアルやってみた!

はじめに ブロックチェーンの学習、ポートフォリオをかねて開発,記事を書きました。 エンジニアですが、いつもマニュアル、ドキュメントはほぼ丸投げで Qiitaの記事も初めてで見にくいところがございましたら、ご了承くださいませ。 LINEのAPIをよく利用させていただいており、LINEブロックチェーンについて少しでも理解していただけると幸いです。 本記事について 対象者 初学者、ブロックチェーンの学習をどこから初めていいかわからない方 LINEのブロックチェーンを利用し始める技術者の方 技術 AWS、Docker、Ptyhon、LINE API 、etc... 環境 テストネットのみのリリースになります。 本番ネットワークは申請が必要になります。  参考サイト FinTech Jjournal Blockchain Biz LINE Blockchain Docs 今回作成したGitHub 目次 チュートリアルのゴール LINE BlockChainの構造 LINE BlockChainのサービスの作成 APIの実装、構造 チュートリアルのゴール LINEでブロックチェーンを操作できるようにしたいと思いフロントはLINEMessageで構築しました。 MessageのAPIを利用したことある方であればとても簡単な構成になっています。 テストネットのみのリリースになりますので、テストユーザーへのトークンの送信。 テストユーザーへのNFTの送信になります。 LINE BlockChainチュートリアル サービスを作成する Non-fungibleアイテムトークンを作成する までがLINEのチュートリアルの内容です。 追加分が トークンを送信してみよう NFTを送信してみよう LINE BlockChainの構造 概要 簡単なLINEDveloppersの構造の紹介 サイドチェーン サイドチェーンは親チェーンでトランザクションを作成し、子チェーンで相対するトランザクションを作成し、資産を転送するという手法を取ります。この時SPV(Simplified Payment Verification)と呼ばれるブロックチェーンの全データをダウンロードすることなくトランザクションの検証を行うアプローチを用いています。親チェーンのコインをサイドチェーンに転送するために、親チェーンのコインを親チェーン上の特殊なOutputに送ります。それをアンロックできるのはサイドチェーン上のSPV証明のみとなっています。 NFT NFTとは、「偽造不可な鑑定書・所有証明書付きのデジタルデータ」のこと。暗号資産(仮想通貨)と同じく、ブロックチェーン上で発行および取引される。従来、デジタルデータは容易にコピー・改ざんができるため、現物の宝石や絵画などのような資産価値があるとはみなされなかった。 それでは作業に行きます。 LINE BlockChainのサービスの作成 チャンネルの作成 サービスの作成 API Secretは、サービスを作成する際に一回のみ表示され、一度発行すると再度確認することはできないため、必ずコピーして安全な場所に保管してください。 API KeyとAPI Secretは、LINE Blockchain Developers APIを呼び出す際に使用されます。 Wallteの作成 - Wallet secretは、サービスウォレットを作成する際に一回のみ表示され、一度発行すると再度確認することはできないため、必ずコピーして安全なところに保管してください。 トークンの作成 一度指定したowner walletは変更できません。ご注意ください。 NFTの作成 これでLINEで必要な設定は終わりです。チュートリアルではCLIからのリクエストが書いているのですが、 ヘッダー情報にsignatureが必要になるため、簡単にリクエストができません。 そのため下記のようなクラスなどを用意してテストリクエストしてください。 APIの実装、構造 LineBlockChain.py class LineBlockChain: server_url = env('LBDAPIEndpoint') service_api_key = env('APIKey') service_api_secret = env('APISecret') def getTimestamp(self): path = '/v1/time' headers = { 'service-api-key': self.service_api_key, } res = requests.get(self.server_url + path, headers=headers) return res.json()['responseTime'] def getNonce(self): nonce = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(8)) return nonce def getSignature(self, secret: str, method: str, path: str, timestamp: int, nonce: str, query_params: dict = {}, body: dict = {}): body_flattener = RequestBodyFlattener() all_parameters = {} all_parameters.update(query_params) all_parameters.update(body) signTarget = self.__createSignTarget(method.upper(), path, timestamp, nonce, all_parameters) if (len(query_params) > 0): signTarget += '&'.join('%s=%s' % (key, value) for (key, value) in query_params.items()) if (len(body) > 0): if (len(query_params) > 0): signTarget += "&" + body_flattener.flatten(body) else: signTarget += body_flattener.flatten(body) raw_hmac = hmac.new(bytes(secret, 'utf-8'), bytes(signTarget, 'utf-8'), hashlib.sha512) result = base64.b64encode(raw_hmac.digest()).decode('utf-8') return result def __createSignTarget(self, method, path, timestamp, nonce, parameters: dict = {}): signTarget = f'{nonce}{str(timestamp)}{method}{path}' if(len(parameters) > 0): signTarget = signTarget + "?" return signTarget # NFTを送信 def POST_v1_item_tokens_contractId_non_fungibles_tokenType_mint(self): nonce = self.getNonce() timestamp = self.getTimestamp() method = 'POST' path = '/v1/item-tokens/'+env('ItemContractID')+'/non-fungibles/'+env("NonFungibleTokenType")+'/mint' request_body = { 'ownerAddress': env("WalletAddress"), 'ownerSecret' : env("WalletSecret"), 'name': 'monkMovieTicket', 'toAddress': env("UserAWallet"), } headers = { 'service-api-key': self.service_api_key, 'nonce': nonce, 'timestamp': str(timestamp), 'Content-Type': 'application/json', 'signature' : self.getSignature(self.service_api_secret , method, path,timestamp, nonce , body=request_body ) } res = requests.post(self.server_url + path, headers=headers, json=request_body) return res.json() #トークンを送信 def POST_v1_wallets_walletAddress_service_tokens_contractId_transfer(self): nonce = self.getNonce() timestamp = self.getTimestamp() method = 'POST' path = '/v1/wallets/'+env("WalletAddress")+'/service-tokens/'+env("ServiceContractID")+'/transfer' request_body = { 'walletSecret': env("WalletSecret"), 'toAddress': env("UserBWallet"), 'amount': '10000000' } headers = { 'service-api-key': self.service_api_key, 'nonce': nonce, 'timestamp': str(timestamp), 'Content-Type': 'application/json', 'signature' : self.getSignature(self.service_api_secret , method, path,timestamp, nonce , body=request_body ) } res = requests.post(self.server_url + path, headers=headers, json=request_body) return res.json() LINEのAPIになるので、開発者ファーストに作成されており、APIの利用経験者ではあればブロックチェーンの構築はサクっと可能です。 あとは自由にLINEMessageのAPIを繋げば完成です。 最後に Qiitaの記事を書くのが初めてなので、こうした方がいいよとか、あればコメントください。 もっとここを教えて欲しい!ここをこうした方がいいよ!などもあればコメントください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Yoasobiの歌詞で、GCP APIとTransformersの感情分析結果を比較

Yoasobiの歌詞で、GCP APIとTransformersの感情分析結果を比較 Github(英語バージョン) https://github.com/leolui2004/sentiment_compare 2つの手法の紹介 Google Cloud Platform NLP API GCPは、さまざまな種類のNLP APIを提供します。自分は感情分析をよく使っています。これはスコアとマニチュードの形でテキストの感情を判断できます。 Transformers と BERT BERTは、Googleが提供する優れたNLP事前トレーニング済みモデルであり、Transformersは、NLPタスクを迅速に開発するための優れたライブラリでもあります。今回は、daigo/bert-base-japanese-sentimentという事前トレーニング済みモデルとbert-base-japanese-whole-word-maskingという事前トレーニング済みトークナイザーを使用しました。 手法の違い 分析結果とは別に、2つの手法の主な違いは次のとおりです。 GCP NLP APIは有料です。1か月あたり無料の割り当て(約5,000句)を提供しますが、実際には十分ではないはずです。一方、Transformersと公開の事前トレーニング済みモデルを使用する場合は完全に無料です。ちなみにライブラリを提供するHugging Face社には、プライベートモデルやデータセットのように使用するプランがいくつかあります。 GCPによるNLP APIの使用は、コンピューティングリソースを消費することはめったにありません。基本的には、APIを呼び出して結果を取得するだけです。ただし、事前トレーニング済みモデルとTransformerを使用すると、一部のコンピューティングリソースを消費します(Transformerの使用にかかる時間が下記にデモします)。また、モデルのトレーニングまたはモデルの微調整に必要なリソースと比べて、事前トレーニング済みモデルを直接使用して分析する場合の方が当然消費するリソースが圧倒的に少ないです。 プロセス 紹介 GCP NLP APIとTransformersの入手方法についての説明を割愛しますが、 GCP NLP APIの場合、GCPのドキュメントを読んで、サービスアカウントを作成してAPI jsonキーを取得するのに10分もかかりません。Transformersの場合、自分はTensorflow 2を使用しています。互換性について、Transformersの最新バージョンがTensorflow 2をどの程度サポートしているかわかりません。なので古いバージョン(Transformers==2.10.0)を使用しています。 分析対象としては、日本の有名グループYoasobiの歌詞を使用します。歌詞は常にNLP分析の良いターゲットであり、難しいターゲットです。 歌詞は時代によって変わる 歌詞には珍しい単語が使われている場合があります。 歌詞は通常、感情的な文書が多い 歌詞は、人によって読むと意味が異なる そしてテストのために、それは3つの部分に分かれます パート1:単語(健全性チェックとして) パート2:短い文 パート3:歌詞の一段落または長文 GCP NLP API サンプルコード 必要なライブラリをインポートする import time from google.cloud import language_v1 import os APIを定義し、APIの制限に触れないようにするために、常に0.1秒のバッファーを追加します os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "nlp.json" client = language_v1.LanguageServiceClient() def api_call(text): document = language_v1.Document(content=text, type_=language_v1.Document.Type.PLAIN_TEXT, language='ja') response_sentiment = client.analyze_sentiment(request={'document': document, 'encoding_type': language_v1.EncodingType.UTF8}) result = [] result.append(text) result.append(response_sentiment.document_sentiment.score) time.sleep(0.1) return result ワードリスト(パート1) word = ['優れる','嬉しい','有名','ナイス','夜景','冷静','大人','法律','慎重','日本','革命','チーター','泣かせ','崩れる','落とす','痛み','厳しい'] テストを行う print('テキスト スコア') for i in word: result = api_call(i) print(result) Transformers サンプルコード 必要なライブラリをインポートする from transformers import pipeline, AutoModelForSequenceClassification, BertJapaneseTokenizer 2つの事前トレーニング済みモデルを使用してパイプラインを構築します model = AutoModelForSequenceClassification.from_pretrained('daigo/bert-base-japanese-sentiment') tokenizer = BertJapaneseTokenizer.from_pretrained('cl-tohoku/bert-base-japanese-whole-word-masking') nlp = pipeline("sentiment-analysis",model=model,tokenizer=tokenizer) ワードリスト(パート1) word = ['優れる','嬉しい','有名','ナイス','夜景','冷静','大人','法律','慎重','日本','革命','チーター','泣かせ','崩れる','落とす','痛み','厳しい'] テストを行う print('テキスト スコア') for i in word: print(nlp(i)) 歌詞サンプル 文リスト(パート2、3) lyrics_short = ['素敵な日になっていく', # もう少しだけ '喜びはめぐる', '慌ただしく過ぎる朝', '気持ちが沈んでいく朝', 'もう少しだけ', '喜びが広がる', '小さな幸せを見つけられますように', '涙流すことすら無いまま', # たぶん '目を閉じたまま考えてた', '悪いのは誰だ 分かんないよ', '誰のせいでもない', '一人で迎えた朝', '仕方がないよきっと', '優しさの日々を辛い日々と感じてしまった', '少し冷えた朝だ'] lyrics_long = ['どこか虚しいような そんな気持ち つまらないな でもそれでいい そんなもんさ これでいい', # 群青 '知らず知らず隠してた 本当の声を響かせてよ、ほら', '好きなものを好きだと言う 怖くて仕方ないけど 本当の自分 出会えた気がしたんだ', '思うようにいかない、今日も また慌ただしくもがいてる', '悔しい気持ちも ただ情けなくて 涙が出る', '踏み込むほど 苦しくなる 痛くもなる', '好きなことを続けること それは「楽しい」だけじゃない 本当にできる? 不安になるけど', '何枚でも ほら何枚でも 自信がないから描いてきたんだよ', '周りを見たって 誰と比べたって 僕にしかできないことはなんだ', '大丈夫、行こう、あとは楽しむだけだ', 'さよならだけだった', # 夜に駆ける '初めて会った日から 僕の心の全てを奪った', 'どこか儚い空気を纏う君は 寂しい目をしてたんだ', '涙が零れそうでも ありきたりな喜びきっと二人なら見つけられる', '見惚れているかのような恋するような そんな顔が嫌いだ', '君の為に用意した言葉どれも届かない', '終わりにしたい だなんてさ 釣られて言葉にした時 君は初めて笑った', '騒がしい日々に笑えなくなっていた 僕の目に映る君は綺麗だ', '明けない夜に溢れた涙も 君の笑顔に溶けていく', '繋いだ手を離さないでよ 二人今、夜に駆け出していく', 'ただその真っ黒な目から 涙溢れ落ちないように', # 怪物 'この間違いだらけの世界の中 君には笑ってほしいから', 'もう誰も傷付けない 強く強くなりたいんだよ 僕が僕でいられるように', 'ありのまま生きることが正義か 騙し騙し生きるのは正義か 僕の在るべき姿とはなんだ 本当の僕は何者なんだ 教えてくれよ', '不器用だけれど いつまでも君とただ 笑っていたいから'] 結果 結果を画像で表示 これはテストを実行した後の結果ですが、結果を確認するのは難しいので、表に入れて、いくつかの可視化を追加します パート1結果(ワード) 結果は驚くべきものであり、2つの事前トレーニング済みモデルを使用するTransformersは、一部の単語分析で失敗しました。ネガティブな言葉であるはずの「痛み」、ニュートラルな言葉であるはずの「大人」、「日本」のような言葉ですが、適切にスコアリングできませんでした。 GCP NLP APIもそれほど完璧ではありませんが(たとえば、「崩せる」の場合は+0.4)、パート1では基本的に良好な結果が得られました。 パート2結果(短い文) 短い文になると、平均絶対スコアの差はさらに大きくなります。ただし、今回はGCPとTransformersの両方でそれぞれ良い結果と悪い結果が得られます。ここで、さらに説明するためにいくつか取り上げます。 素敵な日になっていく GCPのスコアは+0.90でしたが、Transformersのスコアは-0.66でした。完全に間違っています。 気持ちが沈んでいく朝 GCPが「気持ちが沈む」という単語を認識できなかった可能性があります。今回、Transformersはうまく機能しました。 悪いのは誰だ 分かんないよ これは興味深いことです。GCPとTransformers両方が完全に反対の方向にスコアリングされています 優しさの日々を辛い日々と感じてしまった これもトリッキーで、ポジティブな単語(「優しさ」)とネガティブな単語(「辛い」)両方が文に含まれており、GCPは文の構造を認識できませんでした パート3結果(歌詞の一段落または長文) パート3は最も難しい部分であり、人によって解釈が異なる場合があります。 1つずつ説明するつもりはありませんが、傾向としてGCPはより保守的であり、約半分は+ 0.2〜-0.2のスコアであり、一方、Transformersは常に高いスコア(ポジティブ、ネガティブでも)を示します。 パフォーマンス(速度)テスト 最後に、Transformersの速度テストも行い、分析を1,000回繰り返しました。これは、APIを使用するのと同じくらい高速で、30秒未満でタスクを完了したことを示しています。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

深層強化学習(Double-QLearning)を用いたシステムトレーディング

はじめに  近年、人工知能ブームにより、人工知能を使ったトレーディング手法が盛んである。そこで、今回は深層強化学習を用いたシステムトレーディングを実施した。  まず、実際の深層強化学習モデルである。agentの行動として、 BUY、HOLD、SELLの三つの内一つを選択する。環境の戻り値として、状態(今現在保有しているポジションの価格、市場価格、手持ちのキャッシュ)、報酬(手持ちのキャッシュの変化値(含む益も含む))、終了(取引の終了か否か)、情報(ターミナルにディスプレイする情報)を返す。 使用データについて トレンド傾向の掴みやすさから、yahoo financeからGSPCの日足を使用した。 訓練データの期間:2015/1/1 - 2017/6/30 テストデータの期間:2017/7/1 - 2021/1/1 以下ソースコード Double-QLearning1 Q-Learningモデル \tilde{Q}(S_t, a) = R_{t+1}+\gamma \max _{a} Q\left(S_{t+1}, a; \boldsymbol{\theta}_{t}\right) Double-QLearningでは以下の二つの式を用いる。 学習過程 \tilde{Q}(S_t, a) = R_{t+1}+\gamma Q\left(S_{t+1}, \operatorname{argmax}_{a} Q\left(S_{t+1}, a ; \boldsymbol{\theta}_{t}\right) ; \boldsymbol{\theta}_{t}'\right) 行動選択過程 a = \operatorname{argmax}_{a} Q\left(S_{t+1}, (a + a')\right) 実際のコードは以下のようになる。 学習 if s_flag == 11: q = self.model.predict(state) next_q = self.model_2.predict(next_state) t = np.copy(q) if done: t[:, action] = reward else: t[:, action] = reward + self.gamma*np.max(next_q, axis=1) self.model.train_on_batch(state, t) else: q = self.model_2.predict(state) next_q = self.model.predict(next_state) t = np.copy(q) if done: t[:, action] = reward else: t[:, action] = reward + self.gamma*np.max(next_q, axis=1) self.model_2.train_on_batch(state, t) 2つもモデルを用意する。(Q1、Q2とする) 行動には、3つのパターンがある。 1. Q1、Q2を足し合わせた行動 2. Q1、Q1を足し合わせた行動 3. Q2、Q2を足し合わせた行動 実際の行動は1のみ。 学習を行うのは2、3のどちらか一方を1/2の確率で選択する。 行動選択 def act(self, state,s_flag=12): if np.random.rand() <= self.epsilon: return np.random.choice(self.action_size) act_values = self.brain.predict(state,s_flag) if self.epsilon > self.epsilon_min: self.epsilon *= self.r return np.argmax(act_values[0]) 売買ルール 1.空売りは認めない 2.ポジションを持っている場合、追加注文を出せない。 3.最後のステップでポジションを全て売却する。 4.ポジションは全買い、全売り 5.所持金は1000000ドル 実装と結果 qlearningより、勝率、収益率の向上が見られる。 ソースコードはこちら ソースコードはこちら H. van Hasselt, "Double Q-learning", Advances in Neural Information Processing Systems,(2010), 23:2613–2621 ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Djangoの初期設定〜HelloWorld表示まで(基礎の基礎)

0 はじめに Djangoプロジェクトの初期設定〜HelloWorldの表示までの一連の流れについてまとめました。Djangoでウェブアプリケーションを作成する際の基礎の基礎ですが、開発の最初でかならず踏むステップなので、メモとしても活用いただければと思います。(ご利用は自己責任でお願いします。) 1 仮想環境の作成とDjangoのインストール Django作業用フォルダの作成 % mkdir python-django 作成したフォルダの下に入って仮想環境の作成。ここでは、virtualという名前の仮想環境を作ります。 python-django % python3 -m venv virtual binフォルダまで移動 python-django % cd virtual virtual % ls bin include lib pyvenv.cfg virtual % cd bin bin % ls Activate.ps1 activate.csh easy_install pip pip3.9 python3 activate activate.fish easy_install-3.9 pip3 python python3.9 仮想環境をアクティベート。 bin % source activate (virtual)がターミナルに表示されることを確認してください。 ※仮想環境を抜ける場合には、"deactivate"と入力してリターンキーを押せばOKです。 Djangoのインストール (virtual) bin % pip3 install django 2 Django作業環境の作成 virtualフォルダの下にDjangoの作業環境を作ってみることにします。 まずは、フォルダの場所を移動してDjangoというフォルダをvirtualフォルダの直下に作ります。 (virtual) bin % cd ../ (virtual) virtual % mkdir Django (virtual) virtual % cd Django firstappという名前でDjangoのプロジェクトを開始します。以下のコマンドと、プロジェクト名を入力してリターンキーを押します。 (virtual) Django % django-admin startproject firstapp Djangoフォルダの下にfirstappというフォルダができていると思います。firstappの下には、firstappというフォルダと、manage.pyというファイルがあります。 このmanage.pyファイルがあるディレクトリに移動した上で以下のmanage.py startappコマンドを実行します。このコマンドではアプリ名を引数として入力しますが、ここではtodoというアプリ名を使うことにします。 (virtual) firstapp % python3 manage.py startapp todo 3.Hello Worldと表示させてみる - 動作解説編 Webアプリケーションのコードを(他言語のフレームワークを含めて)触ったことがない方は、その仕組みを頭に入れた上でコードを書く必要があります。ここでは、Djangoのフレームワークを使ってHelloWorldを表示させる仕組みについて図を用いながら、解説をしておきたいと思います。 ①ウェブサイトからDjangoフレームワークにリクエストが投げられます。 ②最初にfirstapp/urls.pyというファイルでリクエストの受け付けをします。ここには、アプリフォルダに作ったtodo/urls.pyを見に行けということが書いてあるので、そこに飛びます。 ③todo/urls.pyには、views.pyに定義しているhello関数を呼び出せということが書かれているので、views.pyを見にいきます。 ④views.pyのhello関数が定義してあります。テンプレートフォルダにあるbase.htmlというファイル(テンプレート)を呼んできて、そこのobjectというキーに値(hw)を代入してウェブサイトをレンダリングせよということが書かれているので、ここでウェブサイトを合成します。 ⑤④で合成したウェブサイトをブラウザに返します。 単にHelloWorldを表示させるためにここまで面倒なことをやるのか、と思われた方もいるかもしれませんが、この仕組みを使って、1つ1つhtmlファイルを作る必要がなくなり、テンプレートにコンテンツを入れて表示させることができているのです。 4. Hello Worldと表示させてみる - コード編 初期設定として、firstappフォルダのurls.pyを以下のように書き換えます。スタートページは、todoディレクトリのurls.pyを見に行けという内容です。 from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('',include('todo.urls')), ] 次にsettings.pyで、TODOアプリを認識させる必要がありますのでINSTALLED_APPSに'todo.apps.TodoConfig'を追加します。これは、todoフォルダのapps.pyのTodoConfigクラスを参照しています。 settings.py INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'todo.apps.TodoConfig', ] テンプレートを入れるフォルダを作って、settings.pyに登録作業を行います。manage.pyと同じディレクトリに、templatesという名前のフォルダを作成します。そして、settings.pyのTEMPLATESのところに以下の設定をします。 settings.py import os TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] todoフォルダのurls.pyを編集します。firstappフォルダのurls.pyからtodoフォルダのurls.pyに飛んでくるので、todoフォルダのurls.pyに、(後ほど)viewsの中に記載する関数を呼び出すための命令を書きます。 urls.py from django.urls import path from .views import hello urlpatterns = [ path('', hello, name='hello'), ] では次にviews.pyを書いていきます。return renderがここでは肝になりますが、ここでは、requestがされたら、テンプレートとして、base.html(これはこの後作成します)を呼び出してきて、keyとしてobjectが指定されたら、hw(Hello World)を値として呼び出してくるという動作をします。 views.py from django.shortcuts import render def hello(request): hw = 'Hello World!' return render(request, 'base.html', {'object':hw}) base.htmlを以下のように書いておきます。 base.html {{object}} これで準備ができました。以下のコマンドを入力し、URLをクリックしてみてください。Hello World!と表示されるはずです。 (virtual) firstapp % python3 manage.py runserver
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

databricksにおける環境情報を保持した構成ファイル(spark-env.sh、hive-site.xml等)を確認するためのノートブックで実行するBashコマンド群

概要 databricksにおける環境情報を保持した構成ファイル(spark-env.sh、hive-site.xml等)を確認するためのノートブックで実行するBashコマンド群を共有します。 Databricks Workspaceのノートブックで実行することを想定しており、ベースとなる3つのコマンドを提示した上で、重要なファイルを表示するコマンドを共有します。 ベースとなるコマンド 1. 指定したディレクトリの直下にあるオブジェクトを表示 %sh cd {ディレクトリ} find . -maxdepth 1 実施例 %sh cd / find . -maxdepth 1 2. 指定したディレクトリの直下にあるすべてのオブジェクトをツリー形式で表示 %sh cd {ディレクトリ} pwd;find . | sort | sed '1d;s/^\.//;s/\/\([^/]*\)$/|--\1/;s/\/[^/|]*/| /g' 実施例 %sh cd /tmp pwd;find . | sort | sed '1d;s/^\.//;s/\/\([^/]*\)$/|--\1/;s/\/[^/|]*/| /g' 3. 指定したファイルの内容を表示 %sh cat {表示するファイルのパス} %sh cat /tmp/driver-env.sh 重要そうなディレクトリとファイルを表示するコマンド 最上位の階層のディレクトリを表示 %sh cd / find . -maxdepth 1 /databricks/sparkディレクトリのすべてのオブジェクトを表示 %sh cd /databricks/spark pwd;find . | sort | sed '1d;s/^\.//;s/\/\([^/]*\)$/|--\1/;s/\/[^/|]*/| /g' /databricks/sparkディレクトリにあるVERSIONファイルの内容表示 %sh cat /databricks/spark/VERSION /databricks/sparkディレクトリにあるspark-env.shファイルの内容表示 %sh cat /databricks/spark/conf/spark-env.sh /databricks/sparkディレクトリにあるcore-site.xmlファイルの内容表示 %sh cat /databricks/spark/dbconf/hadoop/core-site.xml /databricks/sparkディレクトリにあるspark-config.shファイルの内容表示 %sh cat /databricks/spark/sbin/spark-config.sh /databricks/hiveディレクトリのすべてのオブジェクトを表示 %sh cd /databricks/hive pwd;find . | sort | sed '1d;s/^\.//;s/\/\([^/]*\)$/|--\1/;s/\/[^/|]*/| /g' /databricks/hiveディレクトリにあるhive-site.xmlファイルの内容表示 %sh cat /databricks/hive/conf/hive-site.xml /databricks/driverディレクトリのすべてのオブジェクトを表示 %sh cd /databricks/driver pwd;find . | sort | sed '1d;s/^\.//;s/\/\([^/]*\)$/|--\1/;s/\/[^/|]*/| /g' /databricks/driverディレクトリにあるspark-branch.confファイルの内容表示 %sh cat /databricks/driver/conf/spark-branch.conf /databricks/driverディレクトリにあるpreload_class.lstファイルの内容表示 %sh cat /databricks/driver/preload_class.lst /databricks/commonディレクトリのすべてのオブジェクトを表示 %sh cd /databricks/common pwd;find . | sort | sed '1d;s/^\.//;s/\/\([^/]*\)$/|--\1/;s/\/[^/|]*/| /g' /databricks/commonディレクトリにあるdeploy.confファイルの内容表示 %sh cat /databricks/common/conf/deploy.conf
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Kaggleのnotebookでunzipしたファイルを取り扱うTips

概要 Kaggleで定義されている訓練用・テストデータがzipに固められているものがある。 ローカルで開発している人は容易に解凍ができるが、notebook上だと「/kaggle/input」は配下はread権限しかないため、エラーが出てしまう。 ▼下記のようなエラー OSError: [Errno 30] Read-only file system: '/kaggle/input/~ やっていることはpythonのzip解凍・zip読み込み系ではあるのだが、kaggle内にある他の人が書いたコードを参考にする時に、zip解凍したファイルの読み込み周りで詰まったので、これで解決できたよという意味でまとめる。 ※他に良い方法があれば教えて欲しいですmm 方法 CSVの場合 CSVの場合は「pandas.read_csv([zip名])」を使用すれば読み込むことができる。 import pd as pandas train = pd.read_csv('/kaggle/input/train.csv.zip') CSV形式は以下でQAのやりとりがあり、他でもunzip方法が記載されている。 画像の場合 ファイル出力 対象zip内のファイルを出力してしまう。 「/kaggle/input」配下に出力できないだけなので、作業用の「/kaggle/working」配下に出力する。 import zipfile z = zipfile.ZipFile('/kaggle/input/street-view-getting-started-with-julia/train.zip') z.namelist() # zip内のファイル名一覧を取得 extractall('/kaggle/working') # zip内容を出力 ※ただし、画像が多い場合は対象DirがUI上は重すぎて開けなくなるので、UI上の操作はしないようにする。 imread関数を使用すれば対象画像を読み込むことができる。 画像が連番の場合はrangeなどで画像読み込みすれば楽に取得できる。 from skimage import io train=[io.imread('/kaggle/working/train/'+str(i)+'.Bmp',as_gray=True) for i in range(1,[ラストの連番まで])] namelist()を使用して、配列を回して画像として読み込むこともできると思う。(for文の回し方を変えるだけだと思うので割愛) ファイル名を元にアクティブで読み込んでいく read関数でも取得することができる。 z = zipfile.ZipFile('/kaggle/input/xxxxx/test.zip', 'r') z.namelist() # zip内のファイル名一覧を取得 img_data = z.read('test/xxxx.Bmp') こちらも上記と同様にrangeなどで連番で画像情報を取得するか、namelistで取得する形になる。 参考リンク https://www.kaggle.com/questions-and-answers/56042 https://www.it-swarm-ja.com/ja/python/python%EF%BC%9A%E4%B8%80%E6%99%82%E7%9A%84%E3%81%AB%E8%A7%A3%E5%87%8D%E3%81%9B%E3%81%9A%E3%81%ABzip%E3%81%8B%E3%82%89%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E9%96%8B%E3%81%8D%E3%81%BE%E3%81%99/1041517400/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

alexaスキルをvisual studio codeでデバッグする

本家サイトを参考に、alexaのスキルをvisual studio code(以下vscode)でデバッグ実行するまで環境構築していきます。(言語はpythonです) 下図のようにブレークポイントで止めて、ステップ実行などができます。 環境 OS mac OS 10.15.7(Catalina) visual studio code 1.58.2 python 3.9.4 (homebrewからインストール) 1. Extensionのインストール vscode自体のインストールは割愛します。 vscodeを立ち上げ、メニューCode > Preferences > ExtensionsからExtentionのインストールができます。 Pythonとask(alexa skill kit) toolkitをインストールします。 Extensionのインストールが終わると、アクティビティバー(左端の黒いバー)にalexaの丸いアイコンが出てきます。 それをクリックすると、ログインしてとか出てきますので、指示に従ってください。 2. スキルをダウンロードする vscodeで一からスキルを作ることもできるようですが、ここでは既存のスキルをダウンロードしてみます。 alexaのチュートリアル(第2回、第3回)で作ったスキルを使用します。(バックエンドはalexa-hosted(python)を選びます) ダウンロード先のフォルダを作ります。ここではcoffeeshopとします。 アクティビティバーからalexaを選び、download and edit skill又はimport existing skillをクリックします。 一覧からスキルを選ぶとダウンロード先を聞かれるので先程作ったcoffeeshopフォルダを指定します。 これで、フォルダにlambda_function.pyなどがダウンロードされます。 3. venv仮想環境を構築する 現状スキルをダウンロード出来ましたが、ask_sdk_coreのimportでエラーが出ている状態です。 ライブラリを追加すればいいのですが、alexa関連のライブラリはこのプロジェクトでしか使わないので、全体的なpython環境に追加するのもよくありません。そこでvenvを使ってプロジェクトローカルなpython環境を作ってそこにライブラリを追加する事にします。 venvはpythonに含まれている仮想環境構築ツールなので、すぐに使うことができます。 仮想環境フォルダ名はなんでもいいのですが、ここでは.venvとします。 ターミナル(bash)から、以下のように実行します。 $ cd coffeeshop/ $ python -m venv .venv $ source .venv/bin/activate $ pip install --upgrade pip $ pip install ask_sdk_core $ pip install ask_sdk_local_debug 上記により、coffeeshop/.venv/binにあるpythonが使われるようになり、coffeeshop/.venv/lib/python3.9/site-packages/にライブラリが追加されます。 ask_sdk_coreはlambda_function.pyが参照しているライブラリ、ask_sdk_local_debugはデバッグに必要なライブラリです。 .gitignoreファイルに.venvを入れておきます。 coffeeshop/.gitignore ask-resources.json .ask .vscode .venv lambda/node_modules 4. vscodeから仮想環境を使うように設定する 先程作った仮想環境を、vscodeで使うように設定します。 メニューCode > Preferences > Settingsで設定画面が開きます。 検索エリアにpython: interpretと入力し、Workplaceのpython Default interpreter pathに.venv/bin/pythonと入力します。 もしくは、settings.jsonに以下のように記述します。 coffeeshop/.vscode/settings.json { "python.defaultInterpreterPath": ".venv/bin/python" } 正しく設定できると、画面下部のステータスバーに.venvのpythonが使われてますよ という表示になりますので、確認してください。 もし違っている場合はその部分をクリックすると どのpythonを使うかの選択画面になりますので、設定してください。 またlambda_function.pyを開いて右上の緑色の実行ボタンをクリックするとファイルが単独で実行されますが、下部のterminal(python)でプロンプトに(.venv)がついている事を確認してください。 また実行してエラーが起きていないことも確認してください。単独実行なので何も起きませんが… 5. デバッグ設定 最初にダミーのデバッグ設定を作ります。 メニューRun > Add Configuration… > python > python file debug the currently active python fileで一般的なpythonデバッグ設定を追加します。 これは最終的には消していいのかもしれませんが試してません。 次にメニューRun > Add Configuration… > ASK: Alexa Skills Debugger(Python)でalexaのデバッグ設定を追加します。 launch.jsonを編集してargsのregionをFEにします。(日本の場合) 最終的にlaunch.jsonか以下のようになります。 coffeeshop/.vscode/launch.json { "version": "0.2.0", "configurations": [ { "name": "Debug Alexa Skill (Python)", "type": "python", "request": "launch", "program": "${command:ask.debugAdapterPath}", "python": "${command:python.interpreterPath}", "args": [ "--accessToken", "${command:ask.accessToken}", "--skillId", "${command:ask.skillIdFromWorkspace}", "--skillHandler", "lambda_handler", "--skillFilePath", "${workspaceFolder}/lambda/lambda_function.py", "--region", "FE" ], "console": "internalConsole", "cwd": "${workspaceFolder}/lambda" }, { "name": "Python: Current File", "type": "python", "request": "launch", "program": "${file}", "console": "integratedTerminal" } ] } 6. デバッグ実行 まずはサーバー側を実行します。 アクティビティバーでデバッグをクリックして左上でDebug alexa skillを選んで左上の緑色の実行ボタンをクリックします。(一番最初の画像のようになります) 次はクライアント側です。 アクティビティバーからalexaをクリックして、コーヒーショップ > Test skill > Open Simulatorでalexaコンソールのテストと同じような画面になります。 ここで「コーヒーショップを開いて」など入力します。 ブレークポイントを設定していればそこで止まるのでデバッグできます。 7. アップロード テストが終わったらvscodeからアップロードできます。 アクティビティバーからsource controlをクリックして、変更したファイルのstage、commitします。 アクティビティバーからalexaをクリックしてdeploy skillを選べば、デプロイできます。 まとめ 初めてqiitaに投稿してみましたが、いかがでしょうか。 alexaコンソールでコードをいじるよりは随分ラクになっていると思います。 ただ仕方ないのかもしれませんが、simulatorのレスポンスは遅いです。 何か間違いがありましたらお知らせください。 おまけ コーヒーショップのチュートリアルのpython版コードはこんな感じかなというのを置いておきます。 省略部分はヒナ型から変更していない部分です。 coffeeshop/lambda/lambda_function.py ... # コーヒーショップを開いて class LaunchRequestHandler(AbstractRequestHandler): """Handler for Skill Launch.""" def can_handle(self, handler_input): # type: (HandlerInput) -> bool return ask_utils.is_request_type("LaunchRequest")(handler_input) def handle(self, handler_input): # type: (HandlerInput) -> Response speak_output = "ようこそ。何を注文しますか?" #"Welcome, you can say Hello or Help. Which would you like to try?" return ( handler_input.response_builder .speak(speak_output) .ask(speak_output) .response ) # コーヒー一杯お願い class OrderIntentHandler(AbstractRequestHandler): """Handler for Hello World Intent.""" def can_handle(self, handler_input): # type: (HandlerInput) -> bool return ask_utils.is_intent_name("OrderIntent")(handler_input) def handle(self, handler_input): # type: (HandlerInput) -> Response menu = "" slot = ask_utils.request_util.get_slot(handler_input, "menu") if slot and slot.value: menu = slot.value amount = "1" slot = ask_utils.request_util.get_slot(handler_input, "amount") if slot and slot.value : amount = slot.value # amaount = handler_input.requestEnvelope.request.intent.slots.amount.value speak_output = menu + "を" + amount + "杯、ご注文ありがとうございます" return ( handler_input.response_builder .speak(speak_output) # .ask("add a reprompt if you want to keep the session open for the user to respond") .response ) ... sb = SkillBuilder() sb.add_request_handler(LaunchRequestHandler()) sb.add_request_handler(OrderIntentHandler()) sb.add_request_handler(HelpIntentHandler()) sb.add_request_handler(CancelOrStopIntentHandler()) sb.add_request_handler(FallbackIntentHandler()) sb.add_request_handler(SessionEndedRequestHandler()) sb.add_request_handler(IntentReflectorHandler()) # make sure IntentReflectorHandler is last so it doesn't override your custom intent handlers sb.add_exception_handler(CatchAllExceptionHandler()) lambda_handler = sb.lambda_handler()
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Z3Py 例題 グラフ彩色問題

問題 以下のグラフの各頂点に 1 から 3 の数を割り当て、隣接する頂点の異なるようにせよ。 回答 example_graph_coloring.py from z3 import * V = [Int('v%s' % i) for i in range(1, 5)] edges = [[1, 2], [1, 3], [2, 3], [2, 4], [3, 4]] s = Solver() s.add([And(1 <= V[i], V[i] <= 3) for i in range(4)]) for x, y in edges: s.add(V[x-1] != V[y-1]) print(s.check()) print(s.model()) 出力 sat [v3 = 2, v1 = 3, v2 = 1, v4 = 3] 解説 s.add(V[x-1] != V[y-1]) edge(辺)がつながっているノード間が異なるという制約をつける。 他の例題 Z3Py個人的ポータル へ 前の例題(魔法陣)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Z3Py 例題 部分和問題

問題 集合 {2,3,5,8,13,21,34} の部分集合で, 和が50になるものはあるか? 回答 example_coin2.py from z3 import * X = [2, 3, 5, 8, 13, 21, 34] a = [Bool("a%s" % i) for i in range(len(X))] s = Solver() s.add(Sum([X[i]*a[i] for i in range(len(X))]) == 50) print(s.check()) if s.check() == sat: m = s.model() subset = [] for i in range(len(X)): if m[a[i]] == True: subset.append(X[i]) print(subset) 出力 sat [3, 5, 8, 13, 21] 解説 Bool("a")で、ブーリアン型の変数を定義できる。 Sum()で、入力したものの総和を計算します。(配列でなくてもOK) 例)Sum([a, b, c]) → a + b + c Sum()の詳細 他の例題 Z3Py個人的ポータル へ 前の例題(コイン問題2) 次の例題(魔法陣)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【自然言語処理】AllenNLP v2.6.0 チュートリアル① IMDBデータセットによるネガポジ分類

はじめに 業務効率向上などを見越して、AllenNLPを勉強することになりました。そのため公式チュートリアルをトレースしていこうと思ったのですが、プログラムがそのまま動かなかったので、修正メモがてら記事にまとめます。また、Tutorialは3Stepに分かれているため、Stepごとに記事を分割しようと思います。 2021/07/25現在でチュートリアル内のコードをブラウザ上で実行できるようなのですが、それも動きませんでした。あらら。 AllenNLPは現時点の最新v2.6.0を使用します。今回使用したNoteBookです。 AllenNLPとは AllenNLPとは何かについて、公式サイトの紹介文を以下に転記します。 AllenNLPは、Allen Institute for Artificial Intelligenceが開発した、自然言語処理用の深層学習モデルを構築するためのオープンソースライブラリです。PyTorchの上に構築されており、高品質なNLPモデルを簡単に構築したいと考えている研究者、エンジニア、学生などをサポートするために設計されています。最新のNLPに共通するコンポーネントやモデルのための高レベルの抽象化とAPIを提供しています。また,実験や実験結果の管理を容易にする拡張可能なフレームワークを提供しています。 実装済みのNLP共通の処理やモデルを利用でき、さらにそれを用いた実験の管理までサポートしてくれるフレームワークということですね。 AllenNLP基礎知識 以下ではAllenNLPの基礎知識を紹介します。 データ形式 AllenNLPでは各データはInstanseによって表現されており、以下のようなTextFieldやLabelFieldを持ちます。また、入力されたテキストはDatasetReaderを用いて読み込み、Instanceへの変換が行われます。 基本的な学習の流れ 学習は以下の図のような流れになります。学習中、Instanceのバッチを受け取り、Model.forward()に通し、lossに基づいて、勾配を計算・モデルパラメータの更新を行います。AllenNLPでは学習のループを実装する必要がありませんが、必要に応じて実装可能となっているようです。 IMDBデータセットによるネガポジ分類 ここからチュートリアルStep1のIMDBデータセットを用いたネガポジ分類モデルの作成を通してAllenNLPの実装を見ます。 実行環境 Google Colaboratory 準備 AllenNLPチュートリアルが提供するIMDBデータをgithubからダウンロードします。以下のコマンドを実行し、データが格納されているquick_startをカレントディレクトリに配置します。パスが公式チュートリアルのプログラムに沿うようにしています。 !git clone https://github.com/allenai/allennlp-guide.git !cp -r ./allennlp-guide/quick_start . また、allennlpのパッケージをインストールします。 !pip install allennlp==2.6.0 プログラムの全体像 プログラムの全体的な流れは以下のようになります。1.ファイル読み込み器の作成,2.訓練・検証データ読み込み,3.語彙の定義,4.データローダーの作成,5.分類モデルの定義,6.訓練の順です。馴染み深い流れですね。 6.訓練のみよくわからないことをやっています。serialization_dirは学習過程の出力ファイルやモデルを保存するためのディレクトリになります。では、tempfile.TemporaryDirectory()は何かというと一時退避ディレクトリになります。プログラム実行時には生成されますが、実際にディレクトリが存在するわけではなく、プログラムが終了次第ディレクトリは削除されます。これは公式チュートリアルの環境で実行する際に必要らしいのですが、Colabでの実行の際には必要ありません。 次に以下プログラムの関数やクラス群が何を表しているかを簡単に見ていこうと思います。 def run_training_loop(): # 1. ファイル読み込み・Instance生成器の作成 dataset_reader = ClassificationTsvReader() # 2. 訓練・検証データ読み込み train_data, dev_data = read_data(dataset_reader) # 3. 語彙の定義 vocab = build_vocab(train_data + dev_data) # 4. データローダーの作成 train_loader, dev_loader = build_data_loaders(train_data, dev_data) # データを語彙でインデックス付けする train_loader.index_with(vocab) dev_loader.index_with(vocab) # 5. 分類モデルの定義 model = build_model(vocab) # GPU or CPU選択 model = model.to(DEVICE) # 6. 訓練 with tempfile.TemporaryDirectory() as serialization_dir: trainer = build_trainer(model, serialization_dir, train_loader, dev_loader) # trainer = build_trainer(model, "./output", train_loader, dev_loader) trainer.train() return model, dataset_reader model, dataset_reader = run_training_loop() vocab = model.vocab 1. ファイル読み込み・データInstance生成クラス 以下でファイル読み込み・データInstance生成クラスを定義します。今回このクラスでは空白を挟んで並んだ単語列を、空白を境に分割し(WhitespaceTokenizer)、各単語を一意のIDに読み替えます(SingleIdTokenIndexer)。またメンバ関数として、トークン列とラベルをまとめて一つのインスタンスに置き換えるtext_to_instance関数と、TSVファイルを読み込んで、TextとLabelをまとめて一つのインスタンスにする_read関数を持っています。 厳密にはDatasetReaderが持っているtext_to_instanceと_readをoverridesして定義しています。これらの定義は必須のようで、継承元のプログラムにはraise NotImplementedErrorの一文しか書かれていませんので、ご注意を。 class ClassificationTsvReader(DatasetReader): def __init__( self, tokenizer: Tokenizer = None, token_indexers: Dict[str, TokenIndexer] = None, max_tokens: int = None, **kwargs ): super().__init__(**kwargs) self.tokenizer = tokenizer or WhitespaceTokenizer() self.token_indexers = token_indexers or {"tokens": SingleIdTokenIndexer()} self.max_tokens = max_tokens @overrides def text_to_instance(self, tokens: List[Token], label: str = None) -> Instance: """トークン列とラベルをまとめて一つのインスタンスに置き換える """ if self.max_tokens: tokens = tokens[: self.max_tokens] text_field = TextField(tokens, self.token_indexers) fields: Dict[str, Field] = {"text": text_field} if label: fields["label"] = LabelField(label) return Instance(fields) @overrides def _read(self, file_path: str) -> Iterable[Instance]: """ファイルを読み込んで、`TextField`と`LabelField`をまとめて一つのインスタンスにする """ with open(file_path, "r") as lines: for line in lines: text, sentiment = line.strip().split("\t") tokens = self.tokenizer.tokenize(text) if self.max_tokens: tokens = tokens[: self.max_tokens] text_field = TextField(tokens, self.token_indexers) label_field = LabelField(sentiment) yield Instance({"text": text_field, "label": label_field}) 2.訓練・検証データ読み込み 訓練・検証データの読み込みを行います。ファイルパスを入力すると、各データがInstanceとなって配列形式で返ってきます。 def read_data(reader: DatasetReader) -> Tuple[List[Instance], List[Instance]]: print("Reading data") training_data = list(reader.read("quick_start/data/movie_review/train.tsv")) validation_data = list(reader.read("quick_start/data/movie_review/dev.tsv")) return training_data, validation_data 3.語彙の定義 Instancesから語彙を定義します。簡単ですね。 def build_vocab(instances: Iterable[Instance]) -> Vocabulary: print("Building the vocabulary") return Vocabulary.from_instances(instances) 4.データローダーの作成 データローダーの作成です。訓練・検証データ各々で作成し、バッチサイズを8と指定しています。 def build_data_loaders( train_data: List[Instance], dev_data: List[Instance], ) -> Tuple[DataLoader, DataLoader]: train_loader = SimpleDataLoader(train_data, 8, shuffle=True) dev_loader = SimpleDataLoader(dev_data, 8, shuffle=False) return train_loader, dev_loader 5.モデル定義 以下で分類モデル定義します。今回作成するモデルは以下のようなモデルです。トークンID列を単語ベクトルに直し(2次元配列状)、次にテキストベクトル(1次元配列状)に直して、最後にLinear層で学習を行います。 以下プログラムでは、forward関数でモデルを定義しています。self.embedderがword embeddingsへの変換、self.encoderがsequence embeddingsへの変換を行う層に当たり、最後にLinear層で分類を行っています。また、util.get_text_field_maskはバッチごとに系列長を揃えるためのパディングを行っています。 class SimpleClassifier(Model): def __init__( self, vocab: Vocabulary, embedder: TextFieldEmbedder, encoder: Seq2VecEncoder ): super().__init__(vocab) self.embedder = embedder self.encoder = encoder num_labels = vocab.get_vocab_size("labels") self.classifier = torch.nn.Linear(encoder.get_output_dim(), num_labels) self.accuracy = CategoricalAccuracy() def forward( self, text: TextFieldTensors, label: torch.Tensor = None ) -> Dict[str, torch.Tensor]: # print("In model.forward(); printing here just because binder is so slow") # Shape: (batch_size, num_tokens, embedding_dim) embedded_text = self.embedder(text) # Shape: (batch_size, num_tokens) mask = util.get_text_field_mask(text) # Shape: (batch_size, encoding_dim) encoded_text = self.encoder(embedded_text, mask) # Shape: (batch_size, num_labels) logits = self.classifier(encoded_text) # Shape: (batch_size, num_labels) probs = torch.nn.functional.softmax(logits) # Shape: (1,) output = {"probs": probs} if label is not None: self.accuracy(logits, label) output["loss"] = torch.nn.functional.cross_entropy(logits, label) return output def get_metrics(self, reset: bool = False) -> Dict[str, float]: return {"accuracy": self.accuracy.get_metric(reset)} 6.訓練準備 ここで訓練を行う準備です。勾配計算を行うパラメータの列挙、最適化関数の設定、学習方法の指定を行い、Trainerオブジェクトを生成します。メイン部分に戻り、trainer.train()で訓練が始まります。 def build_trainer( model: Model, serialization_dir: str, train_loader: DataLoader, dev_loader: DataLoader, ) -> Trainer: parameters = [(n, p) for n, p in model.named_parameters() if p.requires_grad] optimizer = AdamOptimizer(parameters) # type: ignore trainer = GradientDescentTrainer( model=model, serialization_dir=serialization_dir, data_loader=train_loader, validation_data_loader=dev_loader, num_epochs=5, optimizer=optimizer, ) return trainer 訓練過程は以下のようになりました。 訓練過程 Reading data building vocab: 100%|##########| 1800/1800 [00:01<00:00, 1481.02it/s] You provided a validation dataset but patience was set to None, meaning that early stopping is disabled accuracy: 0.7762, batch_loss: 0.1948, loss: 0.4676 ||: 100%|##########| 200/200 [00:04<00:00, 44.60it/s] accuracy: 0.8500, batch_loss: 0.3786, loss: 0.3854 ||: 100%|##########| 25/25 [00:00<00:00, 482.24it/s] accuracy: 0.9881, batch_loss: 0.0208, loss: 0.0576 ||: 100%|##########| 200/200 [00:04<00:00, 47.53it/s] accuracy: 0.8150, batch_loss: 0.6130, loss: 0.4054 ||: 100%|##########| 25/25 [00:00<00:00, 489.77it/s] accuracy: 1.0000, batch_loss: 0.0070, loss: 0.0105 ||: 100%|##########| 200/200 [00:04<00:00, 46.06it/s] accuracy: 0.8250, batch_loss: 0.4147, loss: 0.3643 ||: 100%|##########| 25/25 [00:00<00:00, 482.15it/s] accuracy: 1.0000, batch_loss: 0.0005, loss: 0.0036 ||: 100%|##########| 200/200 [00:04<00:00, 46.01it/s] accuracy: 0.8300, batch_loss: 0.3910, loss: 0.3648 ||: 100%|##########| 25/25 [00:00<00:00, 419.68it/s] accuracy: 1.0000, batch_loss: 0.0032, loss: 0.0019 ||: 100%|##########| 200/200 [00:04<00:00, 46.49it/s] accuracy: 0.8350, batch_loss: 0.3851, loss: 0.3682 ||: 100%|##########| 25/25 [00:00<00:00, 536.92it/s] 予測 最後に学習したモデルを用いて、任意のデータで予測を行います。予測用のクラスとしてPredictorを継承した以下のクラスを定義します。これはテキスト分類用の予測クラスです。AllenNLPでは予測用のクラスをタスクに応じて自作する必要があります。ただし、典型的なタスクにおいては事前に準備されているものがあるようです。詳しくはドキュメント参照。 class SentenceClassifierPredictor(Predictor): def predict(self, sentence: str) -> JsonDict: return self.predict_json({"sentence": sentence}) @overrides def _json_to_instance(self, json_dict: JsonDict) -> Instance: sentence = json_dict["sentence"] sentence = self._dataset_reader.tokenizer.tokenize(sentence) print(sentence) return self._dataset_reader.text_to_instance(sentence) predictor = SentenceClassifierPredictor(model, dataset_reader) output = predictor.predict("A good movie!") print( [ (vocab.get_token_from_index(label_id, "labels"), prob) for label_id, prob in enumerate(output["probs"]) ] ) output = predictor.predict("This was a monstrous waste of time.") print( [ (vocab.get_token_from_index(label_id, "labels"), prob) for label_id, prob in enumerate(output["probs"]) ] ) 実行結果は以下となり、良さそうな結果が得られました。 実行結果 [A, good, movie!] [('neg', 0.47265103459358215), ('pos', 0.5273489952087402)] [This, was, a, monstrous, waste, of, time.] [('neg', 0.5896211266517639), ('pos', 0.41037890315055847)] まとめ 以上でStep1のチュートリアルを終わります。今回Pythonのプログラムから学習を行いましたが、configファイルやコマンドからモデルを作成することも出来ます。方法は改めてまた追加できると良いかなと思っています。変なことを書いてたらご指摘くださると幸いです。 参考文献 公式チュートリアル
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ギリシャ文字をコードに直して加算して出力:glc

ギリシャ文字をコードに直して加算して出力します。 アルファ〜オメガまでの24個の文字を、文字列の中から一つずつ抽出して、加算します。 アルファは1、ベータは2、・・・、オメガは24に相当します。 大文字、小文字は区別しません。 2021/7/25/12:30 改定 ver 1.2 .upper()を使用して、簡略化 2021/7/25/13:30 ver 1.3 .find()を使用して、文字の存在判定を省略 2021/7/25 14:00 ver 1.4 for ループを内包表記にして簡略化 今の所、アクセント記号(モノトニコ)は扱えません。 glc.py #!/usr/bin/python3 import sys argvs = sys.argv argc = len( argvs ) greekc = "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ" if argc != 2: exit(1) v = argvs[1].upper() s = sum(greekc.find(c) + 1 for c in v) print(s) exit(0) 実行例 $ glc.py Υπολογιστη 133
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Pythonの基礎文法

pythonの基礎を全くせず、JSの感覚でやっていたため、改めて知らなかったことをメモ。 リストのindexに負の数を入れて末尾から選択 lst = [1,3,5,7,9] print(lst[-1]) # 9 print(lst[-2]) # 7 リストのindexを指定して新たな値を挿入する lst = [1,3,5,7,9] lst.insert(2,4) print(lst) #[1,3,4,5,7,9] リストの任意の値を削除 lst = [1,3,5,7,9] lst.remove(5) print(lst) #[1,3,7,9] リストの任意の値のindexを検索 lst = ["りんご","みかん","ぶどう","ばなな"] idx = lst.index('みかん') print(idx) # 1 リストやタプル、文字列のようなシーケンスを変数展開(アンパック) x, y, z = ["りんご","みかん","ぶどう"] print(z) # ぶどう set型で集合を表す s1 = {1,4,7} s2 = {2,5,7} シーケンスからsetを作成 s = set(["りんご","みかん","ぶどう"]) print(s) # {"りんご","みかん","ぶどう"} setに値を追加 s = {1,3,7,9} s.add(5) print(s) # {1, 3, 5, 7, 9} setの任意の値を削除 s = {1,3,7,9} s.remove(3) print(s) # {1, 7, 9} setの値の有無を判定 s = {1,3,7,9} print(3 in s) # True 集合の論理演算 s1 = {'A', 'B', 'C'} s2 = {'C', 'D', 'E'} # 和集合 s = s1.union(s2) print(s) # {'D', 'E', 'B', 'C', 'A'} # 積集合 s = s1.intersection(s2) print(s) # {'C'} # 差集合 s = s1.difference(s2) print(s) # {'A', 'B'} s = s2.difference(s1) print(s) # {'D', 'E'} 入れ子のリストから辞書型作成 lst = [['A',1],['B',2],['C',3]] dict = dict(lst) print(dict) # {'A': 1, 'B': 2, 'C': 3} get()を使った辞書型の値を取得 d = {'A': 1, 'B': 2, 'C': 3} value = d.get('B') print(value) # 2 # キーがない場合 value = d.get('D') print(value) # None # キーがない場合挿入する value = d.get('D', 4) print(value) # 4 get()を使った辞書型の値を取得 d = {'A': 1, 'B': 2, 'C': 3} value = d.get('B') print(value) # 2 辞書型のkey, value, itemをlistに変更 d = {'A': 1, 'B': 2, 'C': 3} key_list = list(d.keys()) value_list = list(d.values()) item_list = list(d.items()) print(key_list) # ['A','B','C'] print(value_list) # [1,2,3] print(item_list) # [('A', 1), ('B', 2), ('C', 3)] 2つのリストで辞書型を作る keys = ['A','B','C'] values = [1, 2, 3] dict = dict(zip(keys, values)) # dict ={k: v for k, v in zip(keys, values)} print(dict) # {'A': 1, 'B': 2, 'C': 3} 逆順でループ keys = ['A','B','C'] for key in reversed(keys) print(key) for key in keys[::-1] print(key) リストの内包表記 values = [1, 2, 3, 4, 5, 6, 7, 8] # 偶数をはじく場合 new_list = [value for value in values if value % 2] print(new_list) # [1, 3, 5, 7] # elseを使う場合 new_list = [value if value % 2 == 0 else 0 for value in values] print(new_list) # [0, 2, 0, 4, 0, 6, 0, 8] 可変長な位置引数を使う def func(x, y, *args): numerator = x + y denominator = sum(args) return numerator / denominator a = func(100,200,1,2,3) print(a) 可変長な位置引数とキーワード引数を使う def func(a, b, *args, **kwargs): numerator = a + b denominator = sum(args) const = sum(list(kwargs.values())) return const * numerator / denominator a = func(100,200,4,5,6,x=1,y=2,z=3) print(a) 関数でリストのアンパック def func(x,y,z): return x + y + z lst = [1,2,3] print(func(*lst)) 関数で辞書型のアンパック def func(x,y,z): return x + y + z dict= {"x":1,"y":2,"z":3} print(func(**dict)) 引数がない場合のデフォルト引数 def func(x,y=5,z=3): return x + y + z print(func(2)) # 10 print(func(2,1)) # 6 def func(num, arg=[]): arg.append(num) return arg print(func(2)) print(func(2)) print(func(2)) print(func(2)) # [2] # [2, 2] # [2, 2, 2] # [2, 2, 2, 2] グローバル変数を関数で変える場合 count = 0 def func(x): global count count +=x func(2) func(3) func(4) print(count) # 9 クロージャで関数内の変数を記憶 def func1(): count = 0 def func2(): nonlocal count count += 1 return count return func2 a = func1() print(a()) # 1 print(a()) # 2 print(a()) # 3 lambda式 lst = [2, -10, 5, -3, 6, 7, -8] lst = list(map(lambda x: int(x+1), lst)) print(lst) デコレーターを使ってある関数に対し指定した高階関数を呼び出す def hello_world(func): print('hello') func() @hello_world def world(): print('world') world # hello # world ジェネレーターを使う def hello_world(): yield 'hello' yield 'world' yield '!!' say_sth = hello_world() print(next(say_sth)) print(next(say_sth)) print(next(say_sth)) # hello # world # !! 数値処理 import math #絶対値 abs(-10)# 10 #合計 sum([10,20])# 30 #最大 max([10,20])# 20 #最小 min([10,20])# 10 #四捨五入 round(123.456)# 123 round(123.456,1)# 123.5 round(123.456,2)# 123.46 round(123.456,-1)# 120.0 #円周率 math.pi # 3.14...(180°) #自然数対数の底 math.e # 2.71... #指数関数 math.exp(1) # 2.71... #対数関数 math.log(8,2) # 3.0 #三角関数 math.sin(math.pi/2) # 1 math.cos(2*math.pi) # 1 math.tan(math.pi/4) # 0.99... math.asin(0) #0 math.acos(1) #0 math.atan(0) #0
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DjangoでWebアプリ開発環境の構築(その①)

はじめに Pythonを使ったスクレイピングアプリや予測モデリングを色々と作ってみた事はあったが、Webシステム開発をPythonでした事はなかったため、新たにDjangoも学んでみようかと思った。 まずはインストールや起動の仕方など簡単なところからまとめていく。 実行環境 【ローカルPC環境-OS】   ・Windows 10 Pro  【ソフト・パッケージ情報】   ・Python3.9系 + Django3.2 手順 1.仮想環境を作成してDjangoをインストール 2.Djangoの起動 3.サンプルアプリの起動 1.仮想環境を作成してdjangoをインストール 仮想環境を作成し、その環境内に入り [Django] をインストールする。 conda install django or pip insatall django 仮想環境の作成の仕方が分からない場合はこちらの記事を参考に。  ■Anacondaで作成   【Anaconda環境における仮想環境の作成】  ■Anacondaを使用しない場合   【Python venvを使って複数の実行環境を管理する】 2.Djangoの起動 ※cmdから操作 ・先程作った仮想環境をActivateにする。 ・新規プロジェクトを作成したいディレクトリに移動   ※なければ事前に作成しておく。 cd [ディレクトリへのパス] ・プロジェクトの作成   django-admin startproject [プロジェクト名]   このコマンドより以下の【プロジェクト名】のフォルダができ、その中に以下のファイルが作成される。 manage.py 【プロジェクト名】 _init_.py asgi.py settings.py urls.py wsgi.py ・Djangoを起動してみる。  python manage.py runserver  ブラウザでhttp://localhost:8000 に接続できれば起動確認はOK 3.サンプルアプリの起動 ・作成したプロジェクトに移動し、Webアプリのテンプレートを展開  cd ./[プロジェクト名]  ※上位階層のプロジェクト名に移動  python manage.py startapp [適当なアプリ名]  このコマンドより【プロジェクト名】フォルダの直下に、【アプリ名】のフォルダが作成され、その中に以下のファイルが作成される。 migrations _init_.py _init_.py admin.py apps.py models.py  (アプリケーションのデータモデル) tests.py views.py アプリの設定と公開設定  ※アプリ名=test_app [プロジェクト名]\settings.py # Build paths inside the project like this: BASE_DIR / 'subdir'. from pathlib import Path import os # デフォルトからの追記部分 # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent TEMP_DIR = os.path.join(BASE_DIR, 'temp')) # デフォルトからの追記部分 # 省略--------------------------- INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'test_app' # デフォルトからの追記部分 ] # 省略--------------------------- TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [TEMP_DIR,], # デフォルトからの変更部分 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] test_app\views.py from django.shortcuts import render from django.http import HttpResponse # Create your views here. def index(request): test_dict = {'temp_str': "This is test String"} return render(request, 'index.html', context=test_dict) # return HttpResponse("Hello Django!") # 最もシンプルな Hello Worldを出す場合 temp\index.html  ※tempフォルダも作成 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>テストタイトル</title> </head> <body> <h1>見出し1</h1> {{ temp_str }} </body> </html> [プロジェクト名]\urls.py # 省略--------------------------- from django.contrib import admin from django.urls import path from django.conf.urls import include from test_app import views # デフォルトからの追記部分 urlpatterns = [ path('admin/', admin.site.urls), path('', views.index, name='index')), # デフォルトからの追記部分 path('test_app/', include('test_app.urls')), # デフォルトからの追記部分 ] # 省略--------------------------- test_app\urls.py (新規作成ファイル) from django.urls import path from test_app import views urlpatterns = [ path('', views.index, name='index'), # デフォルトからの追記部分 ] # 省略--------------------------- ・"Hello Django" の起動確認。  python manage.py runserverでDjangoを起動。  ブラウザで以下のURLにアクセスし、"Hello Django"が表示されればOK   ・http://localhost:8000   ・http://localhost:8000\test_app
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[備忘録]ax+by=cを満たす(x,y)をPythonで求める

はじめに 先日、大学入試の問題を解いていたとき、 ユークリッドの互除法に関する問題の解を調べるため、 Pythonでコーディングを行ったので、備忘録として残します。 Python環境下にて、是非お使いください。 #sympy内の関数を使用 from sympy import * #変数x,yの定義と定数a,b,cの入力 x = Symbol('x') y = Symbol('y') a,b,c = map(int,input("a,b,c=??").split()) #方程式の定義 expr1 = a*x+b*y -c #xを求める expr2 = a*x % b -c%b i = 0 while expr2.subs(x,i) !=0: expr2.subs(x,i) i += 1 #求めたxの値を代入し、yを求める expr1 = expr1.subs(x,i) sol = solve(expr1,y) #出力 print("x="+str(i)) print("y="+str(sol[0])) 使い方 ▶a,b,cは半角スペースで区切り、入力してください。 ▶外部ライブラリにつき、予めインストールを要します。(以下、プロンプトでの入力例) conda install sympy #エラーが起これば、下のコマンドを実行してください。 pip install sympy
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PyTorch Lightning の API を勉強しよう

はじめに PyTorch Lightningは生PyTorchで書かなければならない学習ループやバリデーションループ等を各hookのメソッドとして整理したフレームワークです。他にもGPUの制御やコールバックといった処理もフレームワークに含み、可読性や学習の再現性を上げています。 hookには次のようなものが存在します。 class LitModel(pl.LightningModule): def __init__(...): def forward(...): def training_step(...) def training_step_end(...) def training_epoch_end(...) def validation_step(...) def validation_step_end(...) def validation_epoch_end(...) def test_step(...) def test_step_end(...) def test_epoch_end(...) def configure_optimizers(...) def any_extra_hook(...) 学習のループを各hookに分解する様子は、こちらの画像が分かりやすいです。動画もあります。 ということで、PyTorch LightningのAPIについて見てみましょう。 実践的な使い方は参考文献3の解説記事がとても分かりやすいです。 参考文献 公式ドキュメント github PyTorch Lightning 2021 (for MLコンペ) 概要 PyTorch Lightningは最小で二つのモジュールが分かれば良いです。LightningModuleとTrainerです。LightningModuleはtorch.nn.Moduleの拡張のようなクラスで、modelを作成するのに使用します。Trainerは学習のループを実行します。 さらに、データローダーを生成するのにLightningDataModuleを使用すると便利です。モデルの保存やEarly StoppingはCallbackを使用します。 pytorch_lightning.LightningModule 公式ドキュメントはこちら。ソースはここです。 LightningModuleを継承したモデルクラスを作成します。torch.nn.Moduleの作成と似ていますが、ニューラルネットワークのmodelを定義するだけでなく、バッチに対するlossの計算、optimizerまで定義するクラスになっています。作成したモデルをTrainerクラスに渡してfitメソッドで学習を行います。 sample import os import torch from torch import nn import torch.nn.functional as F from torchvision.datasets import MNIST from torch.utils.data import DataLoader, random_split from torchvision import transforms import pytorch_lightning as pl class LitAutoEncoder(pl.LightningModule): def __init__(self): super().__init__() self.encoder = nn.Sequential( nn.Linear(28*28, 64), nn.ReLU(), nn.Linear(64, 3) ) self.decoder = nn.Sequential( nn.Linear(3, 64), nn.ReLU(), nn.Linear(64, 28*28) ) def forward(self, x): # in lightning, forward defines the prediction/inference actions embedding = self.encoder(x) return embedding def training_step(self, batch, batch_idx): # training_step defined the train loop. # It is independent of forward x, y = batch x = x.view(x.size(0), -1) z = self.encoder(x) x_hat = self.decoder(z) loss = F.mse_loss(x_hat, x) # Logging to TensorBoard by default self.log('train_loss', loss) return loss def configure_optimizers(self): optimizer = torch.optim.Adam(self.parameters(), lr=1e-3) return optimizer dataset = MNIST(os.getcwd(), download=True, transform=transforms.ToTensor()) train, val = random_split(dataset, [55000, 5000]) autoencoder = LitAutoEncoder() trainer = pl.Trainer() trainer.fit(autoencoder, DataLoader(train), DataLoader(val)) LightningModuleクラスを継承して、学習の動作をプログラムします。LightningModuleクラスは様々なメソッドを持っており、それらをオーバーライドして使用します。主に、次のコアなメソッドを使用します。 メソッド 必須 内容 __init__(*args, **kwargs) modelやcriterionなどをクラス変数として設定する。 forward(*args, **kwargs) nn.Moduleのforwardと同じだが、主に予測で使用する。クラス内ではself(batch)として呼び出される。 training_step(batch, batch_idx, optimizer_idx, hiddens) ○ DataLaoderをイテレーションして出力したbatchを引数として受け取り、criterionで計算したlossをreturnする。forwardとは独立したメソッド。 validation_step(batch, batch_idx, dataloader_idx) DataLaoderをイテレーションして出力したbatchを引数として受け取り、メトリックを計算する。 test_step(batch, batch_idx, dataloader_idx) DataLaoderをイテレーションして出力したbatchを引数として受け取り、メトリックを計算する。テストデータに対する精度の評価に使用する。テストのラベルを与えられないコンペでは使用しない。 configure_optimizers() ○ optimizerをreturnする。schedulerを使用する場合はreturnをoptimizerのリストとschedulerのリストのタプルとする。 ほぼ確実に使うであろう、他のメソッドも紹介します。 メソッド 必須 内容 training_epoch_end(outputs) 1エポック終わった後の処理をする。各バッチのtraining_stepでreturnした値リストを引数に受け取る。バッチ全体のlossの平均をとったり、バッチ全体の出力を使用して評価指標を計算したりする。 validation_epoch_end(outputs) 1エポック終わった後の処理をする。各バッチのvalidation_stepでreturnした値のリストを引数に受け取る。バッチ全体のlossの平均をとったり、バッチ全体の出力を使用して評価指標を計算したりする。 さらに細かいステップでのメソッドもあります。いくつかありますが、下記を紹介します。 メソッド 必須 内容 backward(loss, optimizer, optimizer_idx, *args, **kwargs) デフォルトはloss.backward()です。 on_after_backward() loss.backward()の後、optmizer.step()の前のタイミング。デフォルトでは何もしない。 optimizer_zero_grad デフォルトはoptimizer.zero_grad()です。 LightningModuleクラスのメソッドとしては定義されていませんが、補助として下記のメソッドを用意して、__init__で呼び出すと便利です。クラスのメソッドとして実装しなくても大丈夫です。 メソッド 必須 内容 create_model() ニューラルネットワークのmodelをreturnします。 create_criterion() Loss Functionsをreturnします。 LightningModuleクラスはデフォルトでLoggerを実装しており、各メソッドの中でlogメソッドでスカラー値のログを取る事ができます。辞書型のログはlog_dictを使用します。 def training_step(self, batch, batch_idx): self.log('my_metric', x) # or a dict def training_step(self, batch, batch_idx): values = {'loss': loss, 'acc': acc, ..., 'metric_n': metric_n} self.log_dict(values) ロガー独特のメソッドを持つ場合は、ロガーを直接呼び出します。 sample from pytorch_lightning.loggers import TensorBoardLogger, TestTubeLogger logger1 = TensorBoardLogger('tb_logs', name='my_model') logger2 = TestTubeLogger('tb_logs', name='my_model') trainer = Trainer(logger=[logger1, logger2]) class MyModule(LightningModule): def any_lightning_module_function_or_hook(self): some_img = fake_image() # Option 1 self.logger.experiment[0].add_image('generated_images', some_img, 0) # Option 2 self.logger[0].experiment.add_image('generated_images', some_img, 0) pytorch_lightning.Trainer Trainerは、学習ループを処理します。データやモデルをGPUに配置したり、学習・バリデーション・テストの実行、コールバックの実行を管理します。 sample from argparse import ArgumentParser def main(hparams): model = LightningModule() trainer = Trainer(gpus=hparams.gpus) trainer.fit(model) if __name__ == '__main__': parser = ArgumentParser() parser.add_argument('--gpus', default=None) args = parser.parse_args() main(args) __init__の引数がとても多いので、主に使用するものを紹介します。 引数 必須 内容 max_epochs 最大エポック数。 min_epochs 最小エポック数。この数までは強制的に学習させる。 max_time 実行する最大時間。Timerコールバックでも同様の設定が可能。 gpus 使用するGPUの数。 callbacks コールバックのリスト。 logger Loggerのリスト。 limit_train_batches 学習で使用するデータの割合を指定する。デバッグ等で使用する。 limit_val_batches バリデーションで使用するデータの割合を指定する。デバッグ等で使用する。 deterministic 非決定論的アルゴリズムを使用するかを決める。 default_root_dir logやweightの保存先のデフォルトルート。各ロガーで指定したパスが優先される。 fast_dev_run 1エポックのみの実行モードになり、学習・バリデーション・テストで実行するバッチ数を指定。デバッグで使用する。これが有効のときはロガー、コールバック、チューナーは実行されない。 flush_logs_every_n_steps ログをディスクに書き込む頻度。 gradient_clip_val 勾配のクリッピングの値を指定。 log_every_n_steps ログをとる頻度。 precision 学習の小数の精度を指定。CPUでは16-bitはサポートされていない。 主に使用するメソッドは下記のとおりです。 メソッド 内容 fit(model, train_dataloaders=None, val_dataloaders=None, datamodule=None, train_dataloader=None) 学習の実行。dataloaderを直接渡してもよいが、管理のためにLightningDataModuleを継承したdatamoduleを渡すほうが良い。 validate(model=None, dataloaders=None, ckpt_path='best', verbose=True, datamodule=None, val_dataloaders=None) 1エポックだけバリデーションを実行する。 test(model=None, dataloaders=None, ckpt_path='best', verbose=True, datamodule=None, test_dataloaders=None) 1エポックだけテストを実行する。 predict(model=None, dataloaders=None, datamodule=None, return_predictions=None, ckpt_path='best') modelのforwardをコールする。 また、知っていると便利なTrainerクラスが持っているプロパティです。 プロパティ 内容 log_dir 現在の実験のディレクトリ。 current_epoch 現在のエポック。 pytorch_lightning.LightningDataModule 公式ドキュメントはこちら。ソースはここです。 各種dataloaderを定義するクラスです。オプションのモジュールですが、dataloaderの再現性のために作成すると良いでしょう。Trainerに渡して使用します。 sample class MNISTDataModule(pl.LightningDataModule): def __init__(self, data_dir: str = "path/to/dir", batch_size: int = 32): super().__init__() self.data_dir = data_dir self.batch_size = batch_size def setup(self, stage: Optional[str] = None): self.mnist_test = MNIST(self.data_dir, train=False) mnist_full = MNIST(self.data_dir, train=True) self.mnist_train, self.mnist_val = random_split(mnist_full, [55000, 5000]) def train_dataloader(self): return DataLoader(self.mnist_train, batch_size=self.batch_size) def val_dataloader(self): return DataLoader(self.mnist_val, batch_size=self.batch_size) def test_dataloader(self): return DataLoader(self.mnist_test, batch_size=self.batch_size) def teardown(self, stage: Optional[str] = None): # Used to clean-up when the run is finished ... mnist = MNISTDataModule(my_path) model = LitClassifier() trainer = Trainer() trainer.fit(model, mnist) LightningDataModuleクラスを継承して、データの準備をプログラムしていきます。主に、次のメソッドを実装します。 メソッド 必須 内容 __init__(train_transforms, val_transforms, test_transforms, dims) transformsやデータの次元をクラス変数に設定する。 prepare_data() データのダウンロード等を行う。 setup() train/val/test splitを行う。 train_dataloader() train_dataloaderをreturnする。 val_dataloader() val_dataloaderをreturnする。 test_dataloader() test_dataloaderをreturnする。 teardown() fitまたはtestの後に行う処理。主に複数GPU並列処理の後処理に使用される。 このクラスはデータに関する情報が含まれるクラスで、Configurationに強く依存するため、Configクラスのようなものを作り、クラス変数に持たせると良いかもしれません。 また、train/valのsplitは、foldを指定出来るようにしておくと、長時間の学習が必要なケースのときに便利です。参考文献3を参照してください。 pytorch_lightning.Callbacks 公式ドキュメントはこちら。 代表的なコールバックを紹介します。 モデルを保存するクラスpytorch_lightning.callbacks.ModelCheckpointです。 ModelCheckpoint( dirpath=None, filename=None, monitor=None, verbose=False, save_last=None, save_top_k=1, save_weights_only=False, mode='min', auto_insert_metric_name=True, every_n_train_steps=None, train_time_interval=None, every_n_epochs=None, save_on_train_epoch_end=None, period=None, every_n_val_epochs=None) ) モデルの汎化性能が上がらないときに学習学習を打ち切るpytorch_lightning.callbacks.EarlyStoppingです。 EarlyStopping( monitor=None, min_delta=0.0, patience=3, verbose=False, mode='min', strict=True, check_finite=True, stopping_threshold=None, divergence_threshold=None, check_on_train_epoch_end=True ) コールバックを自作する場合はpytorch_lightning.callbacks.Callbackを継承し、学習ループ中のhookに該当する抽象メソッドをオーバーライドします。hookはたくさんあるので、こちらの動画でhookの位置を確認しつつ、ソースを見ながら確認したほうが良さそうです。 class Callback(abc.ABC): r""" Abstract base class used to build new callbacks. Subclass this class and override any of the relevant hooks """ def on_configure_sharded_model(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called before configure sharded model""" def on_before_accelerator_backend_setup(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called before accelerator is being setup""" pass def setup(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule', stage: Optional[str] = None) -> None: """Called when fit, validate, test, predict, or tune begins""" pass def teardown(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule', stage: Optional[str] = None) -> None: """Called when fit, validate, test, predict, or tune ends""" pass def on_init_start(self, trainer: 'pl.Trainer') -> None: """Called when the trainer initialization begins, model has not yet been set.""" pass def on_init_end(self, trainer: 'pl.Trainer') -> None: """Called when the trainer initialization ends, model has not yet been set.""" pass def on_fit_start(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when fit begins""" pass def on_fit_end(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when fit ends""" pass def on_sanity_check_start(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when the validation sanity check starts.""" pass def on_sanity_check_end(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when the validation sanity check ends.""" pass def on_train_batch_start( self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule', batch: Any, batch_idx: int, dataloader_idx: int, ) -> None: """Called when the train batch begins.""" pass def on_train_batch_end( self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule', outputs: STEP_OUTPUT, batch: Any, batch_idx: int, dataloader_idx: int, ) -> None: """Called when the train batch ends.""" pass def on_train_epoch_start(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when the train epoch begins.""" pass def on_train_epoch_end( self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule', unused: Optional = None ) -> None: """Called when the train epoch ends. To access all batch outputs at the end of the epoch, either: 1. Implement `training_epoch_end` in the `LightningModule` and access outputs via the module OR 2. Cache data across train batch hooks inside the callback implementation to post-process in this hook. """ pass def on_validation_epoch_start(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when the val epoch begins.""" pass def on_validation_epoch_end(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when the val epoch ends.""" pass def on_test_epoch_start(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when the test epoch begins.""" pass def on_test_epoch_end(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when the test epoch ends.""" pass def on_predict_epoch_start(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when the predict epoch begins.""" pass def on_predict_epoch_end(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule', outputs: List[Any]) -> None: """Called when the predict epoch ends.""" pass def on_epoch_start(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when either of train/val/test epoch begins.""" pass def on_epoch_end(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when either of train/val/test epoch ends.""" pass def on_batch_start(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when the training batch begins.""" pass def on_validation_batch_start( self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule', batch: Any, batch_idx: int, dataloader_idx: int, ) -> None: """Called when the validation batch begins.""" pass def on_validation_batch_end( self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule', outputs: Optional[STEP_OUTPUT], batch: Any, batch_idx: int, dataloader_idx: int, ) -> None: """Called when the validation batch ends.""" pass def on_test_batch_start( self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule', batch: Any, batch_idx: int, dataloader_idx: int, ) -> None: """Called when the test batch begins.""" pass def on_test_batch_end( self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule', outputs: Optional[STEP_OUTPUT], batch: Any, batch_idx: int, dataloader_idx: int, ) -> None: """Called when the test batch ends.""" pass def on_predict_batch_start( self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule', batch: Any, batch_idx: int, dataloader_idx: int, ) -> None: """Called when the predict batch begins.""" pass def on_predict_batch_end( self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule', outputs: Any, batch: Any, batch_idx: int, dataloader_idx: int, ) -> None: """Called when the predict batch ends.""" pass def on_batch_end(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when the training batch ends.""" pass def on_train_start(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when the train begins.""" pass def on_train_end(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when the train ends.""" pass def on_pretrain_routine_start(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when the pretrain routine begins.""" pass def on_pretrain_routine_end(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when the pretrain routine ends.""" pass def on_validation_start(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when the validation loop begins.""" pass def on_validation_end(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when the validation loop ends.""" pass def on_test_start(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when the test begins.""" pass def on_test_end(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when the test ends.""" pass def on_predict_start(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when the predict begins.""" pass def on_predict_end(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when predict ends.""" pass def on_keyboard_interrupt(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called when the training is interrupted by ``KeyboardInterrupt``.""" pass def on_save_checkpoint( self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule', checkpoint: Dict[str, Any] ) -> dict: """ Called when saving a model checkpoint, use to persist state. Args: trainer: the current :class:`~pytorch_lightning.trainer.Trainer` instance. pl_module: the current :class:`~pytorch_lightning.core.lightning.LightningModule` instance. checkpoint: the checkpoint dictionary that will be saved. Returns: The callback state. """ pass def on_load_checkpoint( self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule', callback_state: Dict[str, Any] ) -> None: """Called when loading a model checkpoint, use to reload state. Args: trainer: the current :class:`~pytorch_lightning.trainer.Trainer` instance. pl_module: the current :class:`~pytorch_lightning.core.lightning.LightningModule` instance. callback_state: the callback state returned by ``on_save_checkpoint``. Note: The ``on_load_checkpoint`` won't be called with an undefined state. If your ``on_load_checkpoint`` hook behavior doesn't rely on a state, you will still need to override ``on_save_checkpoint`` to return a ``dummy state``. """ pass def on_before_backward(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule', loss: torch.Tensor) -> None: """Called before ``loss.backward()``.""" pass def on_after_backward(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule') -> None: """Called after ``loss.backward()`` and before optimizers are stepped.""" pass def on_before_optimizer_step( self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule', optimizer: Optimizer, opt_idx: int ) -> None: """Called before ``optimizer.step()``.""" pass def on_before_zero_grad(self, trainer: 'pl.Trainer', pl_module: 'pl.LightningModule', optimizer: Optimizer) -> None: """Called after ``optimizer.step()`` and before ``optimizer.zero_grad()``.""" pass コールバック作成/使用のベストプラクティスは下記です。 コールバックは機能的に分離されていなければなりません。 コールバックは、他のコールバックの動作に依存してはいけません。 コールバックから手動でメソッドを呼び出さないでください。 メソッドを直接呼び出すこと(例:on_validation_end)は強く推奨しません。 可能な限り、コールバックの実行順序に依存しないようにしてください。 Metrics 便利なメトリクスがTorchMetricsというパッケージにまとめられているようです。 TorchMetrics おわりに 頑張って公式ドキュメントを読もう!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AtCoder解説】PythonでABC211のA,B,C,D問題を制する!

ABC211のA,B,C,D問題を、Python3でなるべく丁寧に解説していきます。 ただ解けるだけの方法ではなく、次の3つのポイントを満たす解法を解説することを目指しています。 シンプル:余計なことを考えずに済む 実装が楽:ミスやバグが減ってうれしい 時間がかからない:パフォが上がって、後の問題に残せる時間が増える ご質問・ご指摘はコメントかツイッターまでどうぞ! Twitter: u2dayo よかったらLGTMしていただけると、私のやる気がでます! ほしいものリスト よかったらプレゼントしてくれるとやる気が出るかもしれないです! 目次 ABC211 まとめ A問題『Blood Pressure』 B問題『Cycle Hit』 C問題『chokudai』 D問題『Number of Shortest paths』 アプリ AtCoderFacts を開発しています コンテストの統計データを見られるアプリ『AtCoderFacts』を作りました。 現在のところ、次の3つのデータを見ることができます。 - レート別問題正解率 - パフォーマンス目安 - 早解きで上昇するパフォーマンス 今後も機能を追加していく予定です。使ってくれると喜びます。 ABC211 まとめ 全提出人数: 8604人 パフォーマンス パフォ AC 点数 時間 順位(Rated内) 200 AB---- 300 15分 6271(6047)位 400 AB---- 300 8分 5131(4907)位 600 AB---- 300 3分 4210(3986)位 800 ABC--- 600 19分 3262(3044)位 1000 ABCD-- 1000 75分 2397(2183)位 1200 ABCD-- 1000 47分 1695(1484)位 1400 ABCD-- 1000 30分 1171(962)位 1600 ABCD-- 1000 20分 793(588)位 1800 ABCDE- 1500 98分 508(337)位 2000 ABCDE- 1500 69分 327(178)位 2200 ABCDE- 1500 51分 214(87)位 2400 ABCDE- 1500 29分 147(40)位 色別の正解率 色 人数 A B C D E F 灰 3937 97.9 % 92.3 % 18.2 % 9.4 % 0.1 % 0.0 % 茶 1451 99.5 % 99.3 % 57.5 % 39.1 % 0.6 % 0.0 % 緑 1143 99.7 % 99.7 % 86.4 % 76.8 % 2.0 % 0.1 % 水 669 99.7 % 99.5 % 98.4 % 96.7 % 23.2 % 0.8 % 青 361 100.0 % 100.0 % 100.0 % 99.5 % 45.7 % 7.5 % 黄 171 95.9 % 95.9 % 96.5 % 95.9 % 64.3 % 37.4 % 橙 35 100.0 % 100.0 % 100.0 % 100.0 % 88.6 % 77.1 % 赤 18 100.0 % 100.0 % 100.0 % 100.0 % 100.0 % 100.0 % ※表示レート、灰に初参加者は含めず A問題『Blood Pressure』 問題ページ:A - Blood Pressure 灰コーダー正解率:97.9 % 茶コーダー正解率:99.5 % 緑コーダー正解率:99.7 % 考察 何も考えずに問題文の通りに書けばいいです。 コード def main(): A, B = map(int, input().split()) print((A - B) / 3 + B) if __name__ == '__main__': main() B問題『Cycle Hit』 問題ページ:B - Cycle Hit 灰コーダー正解率:92.3 % 茶コーダー正解率:99.3 % 緑コーダー正解率:99.7 % 考察 $S_i$ として与えられる文字列は必要な文字列 H,2B,3B,HR $4$ 種類のいずれかで、関係ない文字列は与えられません。与えられる文字列が何種類か数えて、$4$ 種類ならば H,2B,3B,HRがすべて $1$ つずつあります。 実装 set型を使って重複を省き、lenで $4$ 種類揃っているか判定するのが楽です。 コード def main(): S_set = set() for _ in range(4): S = input() S_set.add(S) print('Yes' if len(S_set) == 4 else 'No') if __name__ == '__main__': main() C問題『chokudai』 問題ページ:C - chokudai 灰コーダー正解率:18.2 % 茶コーダー正解率:57.5 % 緑コーダー正解率:86.4 % 競プロ典型90問の 008 - AtCounter(★4) と、文字列が異なる以外は全く同じ問題です。 考察 動的計画法です。 最終的に求めたいのは、$N$​ 文字目まで見たときの chokudaiの組み合わせ数です。 chokudai を作るには、それまでにchokudaが必要です。 chokudaを作るには、それまでにchokudが必要です。 chokudを作るには、それまでにchokuが必要です。 chokuを作るには、それまでにchokが必要です。 chokを作るには、それまでにchoが必要です。 choを作るには、それまでにchが必要です。 chを作るには、それまでにcが必要です。 そこで、$i$ 文字目までに c, ch, cho, chok, choku, chokud, chokuda, chokudai それぞれが何回作れるか記録しておきます。 $i$ 文字目までに cho が $100$ 通り、chok が $10$ 通り作れるとします。そして、文字列の $i+1$ 文字目が k だとします。このとき、$i+1$ 文字目までで作れるchok は $100$ 通りの cho に kをくっつけてできる $100$ 通りと、今までに既に作れた$10$ 通りを足して $100 + 10 = 110$​ 通りになります。 実装 二次元リストdp[i][j]で動的計画法をしてもいいですが、一文字前からしか遷移しないので、$i$ 文字目を数えるためのCounterと、$i-1$ 文字目を保存しておくためのCounterの $2$​ つだけあれば良いです。Counterを使うと、添字にchokudaiの英小文字をそのまま使えて楽です。 コード MOD = 10 ** 9 + 7 def main(): from collections import Counter S = input() N = len(S) P = '*chokudai' # 0文字目は英小文字でない適当な記号にします prev = Counter() prev['*'] = 1 # chokudaiのcの遷移のために、*が1通りあることにして初期化します for i in range(N): curr = prev.copy() # copyしないでcurr = prevにすると壊れます char = S[i] for j in range(1, 9): if char == P[j]: curr[char] += prev[P[j - 1]] # 例えばS[i]がoなら、1文字前までのchの組み合わせ数prev['h']をcurr['o']に足します curr[char] %= MOD # 忘れずに10 ** 9 + 7で割った余りをとります prev = curr # ここは prev = currでいいです(次のループでcurr = prev.copy()とするので、同じCounterは参照しません) print(prev['i']) if __name__ == '__main__': main() D問題『Number of Shortest paths』 問題ページ:D - Number of Shortest paths 灰コーダー正解率:9.4 % 茶コーダー正解率:39.1 % 緑コーダー正解率:76.8 % 考察 辺の長さがすべて $1$ のグラフの、頂点 $1$ から他の全頂点への最短経路の長さは、幅優先探索で求めることができます。 幅優先探索を応用して、最短経路の長さだけでなく、最短経路の組み合わせ数も別にカウントすることで解けます。 スタートからゴールまでの最短距離が $3$ だとします。このとき、答えは 『ゴールに繋がっている最短距離が $2$ の頂点への最短経路の組み合わせ数』の合計です。 『最短距離が $2$ の各頂点への最短経路の組み合わせ数』は、『各頂点につながっている最短距離が $1$​​ の頂点への最短経路の組み合わせ数』です。 『最短距離が $1$​ の各頂点への最短経路の組み合わせ数』は、『各頂点につながっている最短距離が $0$​ の頂点(スタート地点)への最短経路の組み合わせ数』です。 コード INF = 1 << 60 MOD = 10 ** 9 + 7 def main(): from collections import deque N, M = map(int, input().split()) edge = [[] for _ in range(N)] for _ in range(M): a, b = map(int, input().split()) a -= 1 b -= 1 edge[a].append(b) edge[b].append(a) dist = [INF] * N dp = [0] * N dist[0] = 0 dp[0] = 1 que = deque((0,)) while que: u = que.popleft() curr_cost = dist[u] next_cost = curr_cost + 1 for v in edge[u]: # INFから更新以外ないです if next_cost < dist[v]: que.append(v) dist[v] = next_cost if next_cost == dist[v]: dp[v] += dp[u] dp[v] %= MOD print(dp[-1]) if __name__ == '__main__': main()
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む