tropicbirdのブログ

備忘録です。

YouTubeを使ったディクテーション学習のWebアプリを作成しました。

作ったWebアプリのご紹介

ディクテーションは、言語学習において非常に有効な手法です。しかし、適切な練習素材を見つけたり、自分の書き取りと正解を比較する作業は、時に面倒です。そこで、YouTubeの動画を活用してディクテーション練習ができるWebアプリ「Dictation with YouTube」を作成しました。英語だけでなく、好きな言語の学習が可能です。

特徴1: 好きな動画が使える

このツールの最大の魅力は、YouTubeにある無数の動画を使ったディクテーション練習ができる点です。興味や学習レベルに応じて、TED Talksからポップカルチャーに至るまで、あらゆるカテゴリの動画を選択し、リスニング力を高めることが可能になります。

特徴2: 字幕との自動比較で学習効率を向上

字幕を手作業で探したり、動画を一時停止して内容を書き取る手間から解放されます。このアプリはYouTubeの字幕を自動的に取得し、それを利用してディクテーションを行います。書き取った内容と即座に正解を照らし合わせられるため、学習効率が飛躍的に向上します。

使用方法

フィードバックをお待ちしてます!

アプリの技術スタック
  • フロントエンド:Next.js
  • バックエンド:FastAPI

ポケモンSV用のファンアプリを作りました。

ポケモンSV向けのスマートフォンアプリを開発しました。非公式なファンアプリです。

アプリの名前は「SV Vision」で、ポケモンバトル中に手元のスマホをテレビやSwitchの画面にかざすだけで、ポケモンのステータスが自動で表示されるというアプリです。

アプリのダウンロード

iOSユーザーの方はこちらから。

SV Vision

SV Vision

  • DAISUKE HORII
  • Utilities
  • Free

Androidユーザーの方はこちらから。

アプリの主な機能

以下に主な機能を紹介します。

  1. カメラ映像からポケモンの名前を読み取り、相手のステータスを自動で表示します。
  2. 自分のパーティを登録すると、Lv50時点のすばやさを自動算出し、相手のすばやさと比較することができます。
  3. SVの全言語のポケモンに対応しています。
  4. レギュレーションDを含むSV解禁済みポケモン全てに対応しています。
メニュー画面
自動読取
すばやさ比較
多言語対応
パーティ登録

アプリ開発の話

アプリの開発に使用した主なフレームワークはFlutterとFastAPIです。AI周りはGoogle's ML Kitを活用しています。

Herokuで公開しているDjangoベースのサイトをBraveクリエイターのに登録する方法

はじめに

自分のサイトをBraveブラウザでクリエイター登録する際に、登録するサイトの./well-knownフォルダに「brave-rewards-verification.txt」を格納してBrave側から認証を得る必要があります。しかし、Djangoで作成してHeroku上で公開しているサイトでは、Herokuにファイルをホスティングする概念がないらしく、TemplateViewを使用したトリッキーな方法をとる必要があります。(他の方法もあるかもですが。)

解決策のソースを見つけるまでに手間取ったので、その方法を記載します。ちなみに私がBraveクリエイターに登録したサイトはこちら

手順(1~9)

1. Braveクリエイターのホーム画面で、「チャンネルを追加」を選択

チャンネルを追加の位置

2. 「ウェブサイト」を選択

ウェブサイトを選択する場合

3. 「認証ファイルを使って認証する」を選択

「認証ファイルを使って認証する」を選択

4. ドメイン情報(サイトのURL)を入力

ドメイン情報(サイトのURL)を入力

5. 画面の指示に従って「brave-rewards-verification.txt」をダウンロードする。

6.「brave-rewards-verification.txt」をDjangoのプロジェクト内のtemplatesフォルダに保存する。

7. Djangoのurlpatternsに以下のパスを追加する。

path('.well-known/brave-rewards-verification.txt', TemplateView.as_view(template_name="brave-rewards-verification.txt", content_type="text/plain"),)

8. Heroku上でDjangoのプロジェクトを再度デプロイする。

9. Braveのチャンネル登録ページに戻り、Verityボタンを押すとBraveクリエイターへのサイトの登録が完了する。これで自分のサイトを通してトークン(Basic Attention Token)の受け取りが可能になる。

ドット絵をNFT化してOpenSeaに出してみた。

自分で描いた動物のドット絵をNFT化してみました。

NFT化したタヌキのドット絵

NFTマーケットOpenSeaの取引高を見てみると、人の手で一つ一つ作られる作品よりも、AIやプログラムを用いて自動で生成する作品(ジェネラティブアート)の方が人気が高いんですね。

ちなみに、24時間の取引高ランキング1位のコレクション(Chimpers)の取引高は13億円!(1ETH=$2,000, $1=120円で計算)すごい笑。

2022年5月21日のOpenSea取引高ランキング、上位はほとんどジェネラティブアート

KaggleのランキングTOP1000(2021年10月4日時点)を調べてみた

はじめに

KaggleのCompetition ランキングのユーザーの属性が気になって調べてみたら、5年前の分析結果(Top-100 Kaggle users by Country)しか見つからなかったので、2021年10月4日時点のCompetitionランキングのTOP1000のユーザーデータをスクレイピングしました。抽出したデータはKaggleのDataset(https://www.kaggle.com/hdsk38/comp-top-1000-data)として公開しています。

⚠️ 注意点
データは2021年10月4日時点のTOP1000ですので、Grandmasterでもコンペがご無沙汰のユーザーは圏外になっています。逆を言うと、「今」のKaggle情勢を示すデータです。

結果(概略)

TOP100ユーザーの国別上位

1位.日本(21名)
2位.アメリカ(14名)
3位.インド、中国、ベトナム(6名、同率)

TOP100ユーザーの数の上位企業

1位.H2O.AI、NVIDIA(8名、同率)
3位.Rist 、Nodalpoint systems、DeNA(2名、同率)

TOP1000ユーザーの国別上位

1位.日本(232名、23.2%)
2位.アメリカ(123名、12.3%)
3位.中国(101名、10.1%)

TOP1000の日本在住ユーザー232名の都道府県の上位

1位.東京(144名、62 %)
2位.神奈川(31名、13 %)
3位.大阪(8名、3 %)

TOP1000の日本在住ユーザー232名の所属組織の上位

1位.DeNA(12名)
2位.Preferred Networks(10名)
3位.Rist(5名)
※なお所属組織非公開ユーザーは半数以上の125名

TOP1000の日本在住ユーザー232名の金メダル数の上位企業

1位.Preferred Networks(43個)
2位.DeNA(39個)
3位.Rist(19個)

TOP1000の日本在住ユーザー232名のポイント数の上位企業

1位.DeNA(293,626 pt)
2位.Preferred Networks(198,779 pt)
3位.Rist(171,641 pt)

結果(詳細)

ライブラリの読み込み

import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
from plotly.offline import init_notebook_mode, iplot, plot
import plotly as py
init_notebook_mode(connected=True)
import plotly.graph_objs as go
import matplotlib.pyplot as plt

データの読み込み

df=pd.read_csv('../input/comp-top-1000-data/top_1000_comp_data.csv')

作図する関数の作成

def bar_plotting(x,y,title):
    trace1 = go.Bar(
                x = x,
                y = y,
                marker = dict(color = 'rgba(255, 174, 255, 0.5)',
                             line=dict(color='rgb(0,0,0)',width=0.5)),
                text = y,)
    layout = go.Layout(barmode = "group")
    fig = go.Figure(data = trace1, layout = layout)
    fig.update_traces(textposition='outside')
    fig.update_layout(
        margin=dict(l=20, r=20, t=40, b=20),
        paper_bgcolor="LightSteelBlue",
        title_text= title,
        title_font_size=20
    )
    fig.update_xaxes(
        tickangle = 90)
    iplot(fig)

国別TOP100

bar_plotting(df[:100].country.value_counts().index,
             df[:100].country.value_counts().values,
             "Countries of top 100 competitors (as of October 4, 2021)")

f:id:tropicbird:20211007210726p:plain

国別TOP1,000

bar_plotting(df.country.value_counts().index,
             df.country.value_counts().values,
             "Countries of top 1000 competitors (as of October 4, 2021)")

f:id:tropicbird:20211007210738p:plain

都道府県別(※TOP1,000に入っている日本在住ユーザー)

bar_plotting(df[df['country']=='Japan'].region.value_counts().index,
             df[df['country']=='Japan'].region.value_counts().values,
             f"Regions in Japan of those who are in top 1000 (n={len(df[df['country']=='Japan'])}, as of October 4, 2021)")

f:id:tropicbird:20211007210803p:plain

所属組織別(※TOP1,000に入っている日本在住ユーザー)

TOP1,000に入っている日本在住ユーザーの所属組織について整理しました。表記ゆれがあるので、まずはユニークな組織を確認します。

print(set(df[df['country']=='Japan'].organization))
{'Recruit Co. Ltd', 'EBILAB', 'kgs go server', 'Operating Room', 'nssol', 'GMO Research, Inc.', 'a JTC', 'ad agency', ' MC Digital, Inc.', 'Microsoft', 'HIOKI E.E.Corporation', 'Yachiyo Engineering Co., Ltd.', 'Astellas  Pharma', 'Rist', 'Hewlett-Packard Japan', 'Research & Technologies company', 'Rist. Z by HP & NVIDIA Data Science Global Ambassador', 'a consulting firm', 'Kyushu', 'Hiroshima Univ.', 'DeNA/Mobility Technologies', 'Keio University', ' Cat cafe', 'XXX', 'DataRobot Japan', 'my home', 'CARTA HOLDINGS', 'University', 'CG production company', 'Consulting company', 'Spectra-Pyisics', '.', 'Fixstars Corp.', 'MNES', 'mixi, Inc', 'Jananese company', 'HOME', 'Kyushu University', ' ', 'ExaWizards', 'Canon Inc.', 'Tokyo Tech', 'general hospital', 'Panasonic Information Systems', '...', 'AXA Life Japan', 'Yahoo! Japan', 'an EC company', 'justforfun', 'Japan Research Institute, Limited', 'GMO Internet', 'Japanese Tech Company', 'GiXo', 'Osaka University', 'japanese company', 'Kyoto', 'Pharmaceutical Company', 'SYS', 'Automaker', 'DMM.com', 'AWS Japan', 'IIT corp', 'DeNA', 'quantum', 'Mitsubishi Electric', 'Mobility Technologies Co., Ltd.', 'Preferred Networks, Inc.', 'UCIrvine', 'Acroquest Technology Co. Ltd.', 'UNKOWN', 'Preferred Networks', 'Japanese Company', 'Technology company', 'consumer electronics company', 'DeNA / Mobility Technologies', 'LINE corp.', 'DentsuDigital', '-----', 'Financial Company', 'astamuse', 'home', 'Kyoto University', 'a', '\u3000', 'EC Service', 'the University of Tokyo', 'hoge', 'VFA', 'Preferred Networks, inc.', ' IT company', 'Automotive Components Manufacturer ', '---', 'Tokyo', 'Aillis Inc.', 'a media company', 'Archaic', 'data-refinement', 'Japanese company', 'Bank', 'Universal Knowledge Inc.', 'Rist Inc.', 'Waseda University', ' Hitachi Ltd.', 'sole proprietorship', 'NVIDIA', 'Recruit', 'human being', 'University of Tsukuba', 'Araya Inc.', 'BioInformatics', 'graduate school', 'Life Insurance Company', 'DeNA Co., Ltd', 'Tech company', 'Mobility Technologies', 'Amazon Web Services', 'NTT DATA', 'Japan', 'Japanese Traditional Company', 'General companies', 'fuga', 'KLTD', 'National Diet Library(国立国会図書館)', 'JTC', 'University of Tokyo', 'a company', ' In the stomach of mom', 'MC Digital, Mitsubishi Group', 'NSSOL', 'Automotive Industry', 'KIOXIA', 'Udacity', 'BrainPad', 'AI Shift', 'THIRD INC.', 'manufacturing company'}

表記ゆれについては、一意の名称に変更し、組織名不明な場合はUNKWONに置き換えます。下記の置換対応は完璧ではないと思うので、漏れや誤りがあればご指摘ください。Kaggle上は組織名不明でもLinkedInのプロフィール等を調べられば組織名が分かるユーザーもいますが、そこまでは対応できていません。

dic_replace={' ':'UNKOWN',
 ' Cat cafe':'UNKOWN',
 ' IT company':'UNKOWN',
 ' In the stomach of mom':'UNKOWN',
 '---':'UNKOWN',
 '-----':'UNKOWN',
 '.':'UNKOWN',
 '...':'UNKOWN',
 'Automaker':'UNKOWN',
 'Automotive Components Manufacturer ':'UNKOWN',
 'Automotive Industry':'UNKOWN',
 'Bank':'UNKOWN',
 'BioInformatics':'UNKOWN',
 'DeNA':'DeNA Co., Ltd',
 'DeNA / Mobility Technologies':'DeNA Co., Ltd',
 'DeNA/Mobility Technologies':'DeNA Co., Ltd',
 'EC Service':'UNKOWN',
 'Financial Company':'UNKOWN',
 'GMO Internet':'GMO Internet Group',
 'GMO Research, Inc.':'GMO Internet Group',
 'General companies':'UNKOWN',
 'HOME':'UNKOWN',
 'JTC':'UNKOWN',
 'Jananese company':'UNKOWN',
 'Japan':'UNKOWN',
 'Japanese Company':'UNKOWN',
 'Japanese Tech Company':'UNKOWN',
 'Japanese Traditional Company':'UNKOWN',
 'Japanese company':'UNKOWN',
 'Kyoto':'Kyoto University',
 'Kyushu':'Kyushu University',
 'Life Insurance Company':'UNKOWN',
 'Mobility Technologies':'DeNA Co., Ltd',
 'Mobility Technologies Co., Ltd.':'DeNA Co., Ltd',
 'Operating Room':'UNKOWN',
 'Pharmaceutical Company':'UNKOWN',
 'Preferred Networks':'Preferred Networks, Inc.',
 'Preferred Networks, inc.':'Preferred Networks, Inc.',
 'Recruit':'Recruit Co. Ltd',
 'Research & Technologies company':'UNKOWN',
 'Rist':'Rist Inc.',
 'Rist. Z by HP & NVIDIA Data Science Global Ambassador':'Rist Inc.',
 'Tech company':'UNKOWN',
 'Technology company':'UNKOWN',
 'Tokyo':'UNKOWN',
 'University':'UNKOWN',
 'a':'UNKOWN',
 'a JTC':'UNKOWN',
 'a company':'UNKOWN',
 'a consulting firm':'UNKOWN',
 'a media company':'UNKOWN',
 'ad agency':'UNKOWN',
 'an EC company':'UNKOWN',
 'consumer electronics company':'UNKOWN',
 'fuga':'UNKOWN',
 'general hospital':'UNKOWN',
 'graduate school':'UNKOWN',
 'hoge':'UNKOWN',
 'home':'UNKOWN',
 'human being':'UNKOWN',
 'japanese company':'UNKOWN',
 'justforfun':'UNKOWN',
 'manufacturing company':'UNKOWN',
 'my home':'UNKOWN',
 'the University of Tokyo':'University of Tokyo',
 '\u3000':'UNKOWN'
}
df['organization']=df['organization'].replace(dic_replace)
data=df[df['country']=='Japan'].organization.value_counts()
data=data.append(pd.Series([len(data[data==1])],index=['Others (one person per organization)']))
data=data[data>1]
bar_plotting(data.index,
             data.values,
             f"Organizations in Japan of those who are in top 1000 (n={len(df[df['country']=='Japan'])},as of October 4, 2021)")

f:id:tropicbird:20211007211331p:plain
TOP1000に2名以上いる組織をプロットしました。所属組織非公開(UNKWON)のユーザーが125名(対象232名の54%)もいるので、実は他にも多くのKgglerがいる組織もあるかもしれません。ちなみに、ランクイン1名の組織はOthersはまとめています。

所属組織別メダル数&ポイント数(※TOP1000の日本在住ユーザー)

TOP1000の日本在住ユーザーの所属組織別のメダル数の上位10位を見てみます。金メダル数ではPreferred Networks、ポイント数ではDeNAが1位でした。

display(df[df['country']=='Japan'].groupby('organization').sum()\
        [['gold','silver','bronze','points']].sort_values(by='gold',ascending=False)\
        .drop(labels='UNKOWN')[:10])
display(df[df['country']=='Japan'].groupby('organization').sum()\
        [['gold','silver','bronze','points']].sort_values(by='points',ascending=False)\
        .drop(labels='UNKOWN')[:10])

金メダル数TOP10
f:id:tropicbird:20211008214019p:plain

ポイント数TOP10
f:id:tropicbird:20211008214032p:plain

最後にTOP100ユーザーの所属組織を見てみます。

df['organization']=df['organization'].str.upper()
#TOP100ユーザーの組織一覧の表示
print(set(df[:100].organization))
#表記ゆれを修正
org_replace_top100={
 'H2O':'H2O.AI',
 'H2O AI':'H2O.AI',
 'KAGGLE':'UNKOWN',
}
df['organization']=df['organization'].replace(org_replace_top100)
data=df[:100].organization.value_counts()
data=data.append(pd.Series([len(data[data==1])],index=['Others (one person per organization)']))
data=data[data>1]
bar_plotting(data.index,
             data.values,
             f"Organizations of those who are in top 100 (as of October 4, 2021)")
{'H2O AI', nan, 'HA NOI UNIVERSITY OF SCIENCE AND TECHNOLOGY', 'TOPCON POSITIONING SYSTEMS', 'MOSCOW STATE UNIVERSITY', "BRIGHAM & WOMEN'S HOSPITAL", 'MAPBOX', '403', 'STEALTH STARTUP', 'DENA CO., LTD', 'H2O', 'KAGGLE', 'O', '-', 'ACROQUEST TECHNOLOGY CO. LTD.', 'YUAN', 'NSSOL', 'NODALPOINT SYSTEMS', 'AACHEN', 'KYOTO UNIVERSITY', 'O.O', 'DAMAE MEDICAL', 'QUANTUM', 'AILLIS INC.', 'DSC ENERGY ANALYTICS', 'VECXOZLAB', 'LINE CORP.', 'IAG', 'AGODA', 'MIPT', 'BAIDU', 'ZALO', 'INTELECY', 'NETAJI SUBASH UNIVERSITY OF TECHNOLOGY, DELHI', 'PREFERRED NETWORKS, INC.', ' HOME', 'TIETO LATVIA', 'RIST INC.', 'UPSTAGE AI', 'PREVISION.IO', 'DIDI', 'STEALTH', 'HOGWARTS', 'UMICH', 'CANON INC.', 'PRAXIS PIONEERING', 'INT', 'MYSELF', 'KHUMBU.AI', 'UNIVERSAL KNOWLEDGE INC.', 'XXX', 'EMBIBE', 'VINGROUP BIG DATA', 'JIO SAAVN', 'CLAIRVOYANT.AI', 'IPPM RAS', 'HIOKI E.E.CORPORATION', 'WASEDA UNIVERSITY', 'NVIDIA', 'UNKOWN', 'SAMSUNG ELECTRONICS', 'SEOUL NATIONAL UNIVERSITY', 'OKCREDIT', 'GRUPO AIA', 'H2O.AI'}

f:id:tropicbird:20211008215132p:plain
予想通りといいますか、NVIDIAとH2O.aiは強いですね。

おわり

AWSとGPUとGCPのGPU(個人利用の場合)

GCPGPUを何回申請しても、割当1つしか認めてもらえなかったが、AWSなら大きめのGPUの申請が一発で通った。

GCPは法人メインだから個人利用者へのGPUの割当が厳しい」という話をTwitterで見たので、そうなのかもしれないです。試しにGoogleカスタマーサービス(?)にGPU割当を相談してみましたがダメでした。

個人でクラウドGPUを使うにはAWS一択なのだろうか。高い。。

GCPで立てたVMにGCSの認証を有効にする方法 解決法⇒ ResumableUploadAbortException: 403 Provided scope(s) are not authorized

エラーメッセージ

ResumableUploadAbortException: 403 Provided scope(s) are not authorized

が出る原因はVMに対してGCSの認証がうまくできていなかったため。
対処方法は以下の通り。

VMのターミナル上で

gcloud init

とし、

Choose the account you would like to use to perform operations for 
this configuration:
 [1] XXXXXXXXXX-compute@developer.gserviceaccount.com
 [2] Log in with a new account
Please enter your numeric choice:

の選択画面で2を選択して既存のGCPのプロジェクトでログインする。

↓ソース
cloud.google.com