2024年6月7日金曜日

Mojo とはPythonのシンプルさとRustのスピードとメモリの安全性を確保しております。 現在はPythonとの完全な互換性はありませんが、PythonインタプリタからPythonとPythonのライブラリを読み込む事が出来ます。 将来的には、互換性を保つプロジェクトを立ち上げたいと考慮配慮しております。互換性を保たせるのをAIにやって頂ければ幸いで御座います。Rustのハイスピードとメモリなどの安全性確保は良いですが、学習が難しいと言うデメリットが御座いますが、それをMojoならハイスピードと、メモリなどのセキュリティの安全性の確保と学習の簡単さを確保出来るPyuthonとRustのハイブリッドな良さがある素敵なプログラム言語のMojoの誕生で御座います。世界中のプログラマーの皆様!お喜びを申し上げます。Google社様、Microsoft社様、MojoをOSやアプリ開発やWEBサイト開発で使用頂ける様になれば、全てがハイスピードでハイセキュリティとなり、ノンストップWEBサーバーによる、ミッションクリティカルによって、一秒間に20万件前後の高速なDATABASEなどによって、世界中の資産家様。このプロジェクトをオープンソース化で、支援して頂けますと、ITやWEBによる様々な産業へのサポート、ペーパーレスやオンライン申請やオンライン貿易などが将来促進されて、交易で国益で御座います。

検索結果はこちら

https://www.google.co.jp/search?q=Mojo+%E3%81%A7Python%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%82%92%E4%BD%BF%E3%81%86&sca_esv=0fe395fae313f6fd&sxsrf=ADLYWIJDjvHfSjKOv2AgpsSNnAfjHwmEpA%3A1717706417055&source=hp&ei=sR5iZrCiAdSqvr0Po7gc&iflsig=AL9hbdgAAAAAZmIswb3xuXRZZsHwnwWcV7tr47ZMx0LI&ved=0ahUKEwjwvsKG68eGAxVUla8BHSMcBwAQ4dUDCA8&uact=5&oq=Mojo+%E3%81%A7Python%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%82%92%E4%BD%BF%E3%81%86&gs_lp=Egdnd3Mtd2l6IiZNb2pvIOOBp1B5dGhvbuODqeOCpOODluODqeODquOCkuS9v-OBhjIJECEYoAEYChgqSNKYAVDwCVjOlAFwCXgAkAEBmAGpAqABnjuqAQcwLjExLjI2uAEDyAEA-AEBmAIloALZK6gCAcICBhCzARiFBMICBxAAGIAEGATCAgUQABiABMICBBAAGB7CAgYQABgKGB7CAgYQABgEGB7CAggQABgEGAoYHsICCBAAGIAEGKIEwgIIEAAYogQYiQXCAgcQABiABBgNwgIHECEYoAEYCpgDA5IHBzkuMTAuMTigB_xb&sclient=gws-wiz

2023/10/24 — 現在はPythonとの完全な互換性はありませんが、Pythonインタプリタを呼び出すことでPythonコード/ライブラリを呼び出すことができ、将来的にはMojo自体が ...


新しいPython風プログラミング言語Mojoを試してみた

2023.10.24

こんにちは。CX事業本部Delivery部のakkyです。

少々旧聞となりますが、今年9月にMojo言語がローカルで実行できるようにリリースされました。

MojoはSwiftの開発者が立ち上げたModular社が開発している新しいプログラミング言語で、Pythonの文法とRustのメモリ安全性を兼ね備えたコンパイラ型プログラミング言語です。

AI開発に使用することが想定されていて、SIMDのファーストクラスサポートなども特徴的です。実際にllama2.mojoというLlama2の実行環境の実装も行われています。

現在はPythonとの完全な互換性はありませんが、Pythonインタプリタを呼び出すことでPythonコード/ライブラリを呼び出すことができ、将来的にはMojo自体がPythonのスーパーセットとなることを目指しているそうです。

10月19日にはMacのApple silicon(ARM)版もリリースされましたので、M1/M2マシンでも試せるようになりました。

Pythonとの関係

文法

関数の定義にdeffnが存在するのが大きな違いです。defはPython互換で型を付ける必要がなく、fnはMojo独自の関数で型定義などをする必要がありますが、大幅に最適化されます。 defで定義された関数もfnで定義された関数も、それぞれ相互に呼び出して使うことができます。

なお、型を付ける必要があるという違いのほか、fnでは例外をきちんと処理しなければならないという違いもあります。詳しくは公式ドキュメントで説明されています。

また、fnでは変数宣言が必要で、let(イミュータブル・変更不可能)とvar(ミュータブル・変更可能)を明示できます。型推論がありますが、明示的に書くこともできます。

ライブラリ

ライブラリの一覧はドキュメントに記載されています。 現在のところ、Python標準ライブラリがすべて実装されているわけではなく、一部の実装に限られています。実装されているものでも引数や使い方が異なっていることがあるので、ライブラリに関しては完全に別物と思っていたほうがいいと思います。

互換性

MojoではPythonのライブラリをインポートして使うことができます。たとえば、次のようなコードを書くと、requestsでHTTPアクセスできます。

from python import Python

def main():
    let requests = Python.import_module("requests")
    let url = "https://checkip.amazonaws.com/"
    let responce = requests.get(url)
    let ip_raw = responce.content.decode()
    let ip_str = ip_raw.strip()
    let message = "your ip address is " + ip_str.to_string()
    print(message)

ただし、この場合requestsライブラリやその後の処理はMojoではなくCPythonのインタプリタが実行するため、高速化はされないようです。

このコードで言うとrequestsオブジェクトはもちろんのこと、ip_rawなどのオブジェクトもPythonのものになります。Mojoの文字列にはstrip()メソッドはないのにこのコードが動くのは、ip_rawはPythonのオブジェクトで、実際の処理はCPythonインタプリタが行っているためです。

REPLで実行すると変数の型が表示されて、urlはmojoネイティブのStringLiteral型ですが、ip_rawPythonObject型になっていることがわかります。

インストール

公式サイトの手順通りに行います。Ubuntu 23.10では、事前にpython3-venvをインストールしておく必要がありました。venvなしでインストールするとエラーになるのですが、この状態では再びmodular install mojoしてもダメで、modular cleanしてからやり直す必要がありました。

実行方法

mojoコマンドでREPLが起動します。ファイルに保存されているスクリプトを実行するときはmojo run ファイル名とします。 なお、ファイル名は.mojoまたは.🔥という拡張子(絵文字も可!)である必要があります。

mojo build ファイル名とすると、コンパイルして実行ファイルを生成することも可能です。

実行速度を実験してみた

Mojoは高速化が大きな目玉とされていますが、実際はどの程度高速化されるのでしょうか?既存のソフトウェアがそのまま動く状態ではないため、簡単なコードでの実験となりますが、比較してみました。比較対象はCPythonとPypyです。

実行速度の測定にはtimeコマンドを使用し、3回実行して最も速いrealの値を記載しました。 実行環境はWSL2上のUbuntu 23.10です。

使用バージョン

  • Mojo 0.4.0
  • Python 3.11.6
  • PyPy 7.3.12 (Python 3.9.17)

フィボナッチ数の計算

まずはフィボナッチ数の計算で比較してみます。

Python/Pypy

import sys

def fibonacci(n):
    if n == 0 or n == 1:
        return n
    else:
        return fibonacci(n - 2) + fibonacci(n - 1)

def main():
    print(fibonacci(int(sys.argv[1])))

main()

Mojo

2バージョンで比較してみます。まずはdefで定義したものです。こちらは型を付けていません。

Pythonコードとの違いは、sys.argv()がプロパティではなく関数である点と、文字列を数値に変換するのにatol()を使うという点です。

import sys

def fibonacci(n):
    if n == 0 or n == 1:
        return n
    else:
        return fibonacci(n - 2) + fibonacci(n - 1)

def main():
    print(fibonacci(atol(sys.argv()[1])))

次にfnで定義したものです。Int型を指定しました。mainもfnとしたので、例外をキャッチして握りつぶすコードを追加しています。

import sys

fn fibonacci(n: Int) -> Int:
    if n == 0 or n == 1:
        return n
    else:
        return fibonacci(n - 2) + fibonacci(n - 1)

fn main():
    try:
        print(fibonacci(atol(sys.argv()[1])))
    except:
        pass

実行速度の比較

引数を40とした場合。

実行環境実行時間(秒)
Mojo(def)8.634
Mojo(fn)0.430
Python17.262
Pypy7.442

Mojoでもdefを使うとあまり高速化しませんが、fnを使うと別物のように高速化しました。

竹内関数の計算

もう一つ、フィボナッチ数の計算と傾向の違いはあまりないと予想できますが、プログラミング言語の処理系のベンチマークに使われる竹内関数も実験してみました。

Python/Pypy

import sys

call_cnt = 0

def tarai(x, y, z):
    global call_cnt
    call_cnt += 1
    if x <= y:
        return y
    else:
        return tarai(tarai(x - 1, y, z), tarai(y - 1, z, x), tarai(z - 1, x, y))

def main():
    arg = sys.argv
    if len(arg) >= 4:
        x = int(arg[1])
        y = int(arg[2])
        z = int(arg[3])

        res = tarai(x, y ,z)
        print(call_cnt)

main()

Mojo

こちらはmainをdefで定義してみました。(実際の処理はtarai関数が行うので、実行速度にほとんど変化はないはずです)

import sys

var call_cnt = 0

fn tarai(x: Int, y: Int, z: Int) -> Int:
    call_cnt += 1
    if x <= y:
        return y
    else:
        return tarai(tarai(x - 1, y, z), tarai(y - 1, z, x), tarai(z - 1, x, y))

def main():
    let arg = sys.argv()
    if len(arg) >= 4:
        let x = atol(arg[1])
        let y = atol(arg[2])
        let z = atol(arg[3])

        let res = tarai(x, y ,z)
        print(call_cnt)

実行速度の比較

引数を13 6 0とした場合。

実行環境実行時間(秒)
Mojo(fn)0.213
Python4.940
Pypy1.528

考察とまとめ

フィボナッチ数や竹内関数のような主に関数の呼び出しがメイン負荷となるベンチマークでは、おおむね20倍程度高速化する傾向があることがわかりました。

実際のワークロードではここまでの差は出ないかもしれませんが、SIMDのネイティブサポートなどによってCPUバウンドな処理ではかなり高速化されそうです。

たとえば、Modular公式ブログではPythonから68,000倍高速化したという記事がありますが、これはMojo自体の速度に加えて、SIMDを活用した高速化とマルチコアCPUを活用した最適化の結果のようです。簡単に並列処理ができるのはとても良いですね。

ただ、現在のところは互換性や機能の不足によって、PythonやPypyを置き換えられるような状態にはなっていません。 今後開発が進み、CPythonとの互換性が高まると、既存のPythonプログラムが手軽に高速化できるようになり、他の言語で開発された拡張モジュールを使う必要がなくなるかもしれません。

AWSへの適用という点を考えると、実行ファイルをコンパイル可能なので、Lambdaの実行が高速になるのに加え、デプロイが簡単になるというメリットがありそうです。Webフレームワークが出てくると楽しそうですね。

今後も引き続き開発の状況を追いたいと思います。

参考ページ

InfoQ Mojoプログラミング言語の紹介

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

Pythonの35000倍速い新言語Mojo🔥 に触れてみた【基礎編】

Mojo🔥とは

PythonのシンプルさとRustのスピードとメモリの安全性を組み合わせた、新しいプログラミング言語。

Pythonの35000倍速いとされており、Pythonの弱点である「遅さ」を補うと期待されている。また、書き方もPythonと似ているので移行もしやすいです。

そんな言語が2023年10月19日より、Appleシリコン搭載Macに対応したとのことで、早速触ってみました。

本家のドキュメントはここにまとまっています。

Mojo🔥のセットアップ

ターミナルやVSCodeで使えるようにセットアップが必要です。

以前記事にまとめたので、そちらをご覧ください

Mojo🔥の基本

主にPythonとの比較をしながら書いていきます。

前提

・Mojo🔥はコンパイル言語であり、他のコンパイル言語たち同様、エントリーポイントとして main() が必要
・Pythonのすべての構文とセマンティクスをサポート(Pythonの書き方でも実行可能)

変数 var, let

var x: Int = 1
let y: Int = 2

varは可変な変数、letは不変な変数の定義に用います。Intなどの型タイプは省略も可能です。

関数 : def → fn

Python:

def main():
    x = 1
    x += 1
    print(x)

Mojo🔥

fn main():
    var x: Int = 1
    x += 1
    print(x)

ただ、defのままでも実行できます。fnにすると型の安全性を強制するようにできます。

なので、fnの中でvarなどを削除するとエラーになります。

また、関数に引数や返り値を設定する場合は、型タイプを明記する必要があります。書かないとエラーが出ます

・OKな例

fn add(x: Int, y: Int = 1) -> Int:
    return x + y

・ダメな例

fn add(x, y):
    return x + y

引数のデフォルト値の設定方法はPythonと同じです

borrowed と inout と owned

関数の引数はimmutableな変数(変更不可)として読み取られます。
従って、以下はエラーになります

fn add(x: Int, y: Int) -> Int:
    x += 1
    return x + y

borrowedはそのことを明記する(保証する)役割らしいです
→関数がそのオブジェクトの所有権を持たず変更しないことを保証している
※borrowedは、特に何も書いていない上のfn add() と同じ挙動になります。
→デフォルトでborrowedが省略されていると考えれば良い?

fn add(borrowed x: Int, borrowed y: Int) -> Int:
    return x + y

さらに、inoutというものがあります。

fn add(inout x: Int, inout y: Int) -> Int:
    return x + y

inoutとして設定すると、引数をmutableな変数(変更可能)とできます。そして関数内部で加えられた変更は外部にも影響します。

fn main():
    var a = 1
    var b = 2
    let c = add_inout(a, b)
    print(a)
    print(b)
    print(c)


fn add_inout(inout x: Int, inout y: Int) -> Int:
    x += 1
    y += 1
    return x + y

これを実行すると、

2
3
5

となります。aは元々1, bは2でしたが、fn add_inout() の中で1ずつ足されたので、それぞれ2, 3になっています。

ownedは、引数をmutable(変更可能)とするものの、関数の外には影響を与えないとするものです。
先ほどのコードでinoutをownedに変更すると、

fn main():
    var a = 1
    var b = 2
    let c = add_inout(a, b)
    print(a)
    print(b)
    print(c)


fn add_inout(owned x: Int, owned y: Int) -> Int:
    x += 1
    y += 1
    return x + y

結果は

1
2
5

となって、aもbも変更されていないことがわかります。

クラス class → struct

完全に静的なclassのようなもので、メソッド、フィールド、オーバーロード、デコレータなどを定義できます。

struct MyPair:
    var first: Int
    var second: Int

    fn __init__(inout self, first: Int, second: Int):
        self.first = first
        self.second = second

    fn dump(self):
        print(self.first, self.second)

fn main():
    let mine = MyPair(2, 4)
    mine.dump()

第一引数にself を渡すところや__init__() を定義するところはPythonのclassと同じです

出力は

2 4

となります。Pythonのclassと違うところとして、__init__() で定義するself.first やself.second は事前にvar first: Int と定義しておく必要があることが挙げられます。これがないとエラーになってしまいます。

error: 'MyPair' value has no attribute 'first'
        self.first = first + 1

また、__init__() の引数はinoutとして渡します。

これは、イニシャライザはオブジェクトの初期化を担当する部分であり、このメソッド内でselfオブジェクトを変更するので引数はmutableでなければなりません。したがってborrowedは適しません。

さらに、selfオブジェクトを変更してこのメソッド外においてもその変更を適用させたいのでownedも適しません。したがって、inoutとする必要があります。

まあ、一言で言えば、「selfはインスタンスを示すので、__init__で行われるインスタンスの初期化をクラス内の他のメソッドでも適用させたいため、inoutとする」ということです。

Pythonライブラリを使う Python integration

ドキュメント通りのコードを実行するとエラーが出る。。。

numpyをうまく読み込めないっぽい。色々調べたけど治らず。
まだ情報が少ないからこういう問題が発生した時の対処が大変です。。

最後に

まだまだMojo🔥は発展途中の言語で、ドキュメントにもそのことは繰り返し書かれていました。Pythonに似ていて書きやすいので今後の発展が楽しみです。

次はPythonとの速さの比較の記事を書こうと思っているので、読んでもらえたら嬉しいです!

また、X(Twitter)では日々データサイエンスやAIに関する勉強記録・情報発信をしています。フォロワーはもうすぐ5500人に到達します。

少しでも刺激になるようなことを発信できたらいいなと思っているので、気になった方は見てみてください🔥

では👋

137
129
1

新規登録して、もっと便利にQiitaを使ってみよう

  1. あなたにマッチした記事をお届けします
  2. 便利な情報をあとで効率的に読み返せます
  3. ダークテーマを利用できます
ログインすると使える機能について
mohki7

@mohki7(Mototsugu Oki)

慶應義塾大学大学院理工学研究科開放環境化学専攻オープンシステムマネジメント専修修士1年。データサイエンティストを目指し、日々奮闘中。統計検定準1級最優秀成績賞。SIGNATE Students Cup 2023 ChatGPT部門SIGNATE賞、特別賞。Twitterフォロワー7000人越え。現在は因果推論・GNN・LLMに興味があり学習中





0 コメント:

コメントを投稿