前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >机器学习|Mojo语言入门

机器学习|Mojo语言入门

作者头像
用户1904552
发布2025-02-27 10:29:09
发布2025-02-27 10:29:09
5500
代码可运行
举报
文章被收录于专栏:周末程序猿周末程序猿
运行总次数:0
代码可运行

1、什么是Mojo

Mojo被设计为Python的超集,如果了解Python,那么Mojo代码的入门也不难。 Mojo旨在解决其他任何语言都无法解决的各种人工智能开发挑战,因为Mojo是第一种从头开始使用MLIR(一种理想的用于异构硬件的编译器基础设施,从CPU和GPU到各种人工智能ASIC)构建的编程语言。

2、安装Mojo

(1)执行:curl -s https://get.modular.com | sh - (2)执行:modular auth,会提示 To complete auth, open this web page:,然后打开对应的链接地址,然后登录到页面,过一会就可以授权到当前你使用的设备 (3)安装 Mojo SDK,执行:modular install mojo (4)最后一步,设置当前环境变量:

代码语言:javascript
代码运行次数:0
复制
MOJO_PATH=$(modular config mojo.path) \
  && BASHRC=$( [ -f "$HOME/.bash_profile" ] && echo "$HOME/.bash_profile" || echo "$HOME/.bashrc" ) \
  && echo 'export MODULAR_HOME="'$HOME'/.modular"' >> "$BASHRC" \
  && echo 'export PATH="'$MOJO_PATH'/bin:$PATH"' >> "$BASHRC" \
  && source "$BASHRC"

(5)查看mojo的版本:mojo --version,退出命令行:ctrl + d (6)更新mojo:modular update mojo (7)在线尝试mojo,可以打开:https://docs.modular.com/mojo/playground

3、hello world

(1)进入命令行:mojo

代码语言:javascript
代码运行次数:0
复制
MacBook-Pro ~ % mojo
Welcome to Mojo! 🔥

Expressions are delimited by a blank line.
Type `:quit` to exit the REPL and `:mojo help` for further assistance.

  1>

(2)输入:print("Hello, world!")

代码语言:javascript
代码运行次数:0
复制
  1> print("Hello, world!")
  2.
Hello, world!

(3)创建hello.mojo文件,然后执行:

代码语言:javascript
代码运行次数:0
复制
fn main():
    print("Hello, world!")

mojo hello.mojo
输出:Hello, world!

(4)编译:

代码语言:javascript
代码运行次数:0
复制
mojo build hello.mojo
./hello
输出:Hello, world!

4、Mojo 语法基础

(1)函数定义:

  • def 允许非类型声明和动态行为(Python 风格)
  • def 定义的函数则不需要声明类型
  • fn 声明强制执行类型检查和内存安全行为(Rust 风格)
  • fn 定义的函数中必须声明参数和返回的类型,除非函数不返回值
  • fn 定义的函数,如果函数引发异常,必须使用 raises 关键字显式声明异常
  • 返回值不声明则为默认的 object 类型
  • 每个程序入口必须包含main函数
  • 函数可以定义可选参数,比如 fn pow(base: Int, exp: Int = 2) -> Int:

(2)函数参数传递:按值传递还是按引用传递

  • def 定义的函数通过值传递参数
  • fn 定义的函数通过不可变引用传递参数

(3)变量声明:可以通过 var 声明变量

  • def 定义的函数声明变量可以忽略 var
  • fn 定义的函数声明的变量类型是可选的
  • 支持多种类型方式声明:var name1: String = "aaa" 或者 var name2 = String("aaa")
  • 使用样例:
代码语言:javascript
代码运行次数:0
复制
fn do_math(x : Int):
    var y : Int = 1
    y = x + y
    y = y * y
    print(y)

(4)结构体:类似的 pythonclass

  • 支持方法、字段、运算符重载、用于元编程的装饰器
  • 结构体必须要构造函数,定义 __init__() 方法,其中 __init__() 方法第一个参数是 inout self
  • 在构造函数中初始化结构体的所有字段(如果尝试将字段留空,则代码将无法编译)
  • 在结构体中可以定义方法,但是第一个参数默认是 self,用于访问当前结构体实例
  • 在结构体中可以定义静态方法,使用 @staticmethod,访问方式用实例或者struct名都可以运行
  • 结构体的魔术方法有:__init____del__等,也可以@value合成__moveinit____copyinit__等结构体方法
  • 使用样例:
代码语言:javascript
代码运行次数:0
复制
struct MyPair:
    var first: Int
    var second: Int
    # var third: Int # 如果不在__init__赋值,就会编译报错

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

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

    @staticmethod
    fn log_info(message: String):
        print("Info: ", message)

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

(5)trait:类似 golanginterfacerusttrait,通过让定义一组共享的行为,让类型可以实现这些行为来解决此问题

  • 创建具有 trait 定义的结构体,必须实现每个 trait 的函数
  • trait 不具备默认的函数方法
  • trait 支持继承,可以让 trait 继承多个其他的 trait
  • 内置的 Traits 例如:AnyType,Boolable,Movable,Stringable,Copyable ...
  • 使用样例:
代码语言:javascript
代码运行次数:0
复制
trait Quackable:
    fn quack(self): ...

@value
struct Duck(Quackable):
    fn quack(self):
        print("Quack")

@value
struct StealthCow(Quackable):
    fn quack(self):
        print("Moo!")

fn make_it_quack[T: Quackable](maybe_a_duck: T):
    maybe_a_duck.quack()

struct MyList(Sized):
    var size: Int
    # ...

    fn __init__(inout self):
        self.size = 0

    fn __len__(self) -> Int:
        return self.size

print(len(MyList()))

(5)元编程

  • 支持参数化函数
  • 支持参数化结构体
  • 支持可变参数,如:fn sum_params[*values: Int]() -> Int:
  • 使用样例:
代码语言:javascript
代码运行次数:0
复制
struct GenericArray[T: AnyRegType]:
    var data: Pointer[T]
    var size: Int

    fn __init__(inout self, *elements: T):
        self.size = len(elements)
        self.data = Pointer[T].alloc(self.size)
        for i in range(self.size):
            self.data[i] = elements[i]

    fn __del__(owned self):
        self.data.free()

    fn __getitem__(self, i: Int) raises -> T:
        if (i < self.size):
            return self.data[i]
        else:
            raise Error("Out of bounds")

(6)值的生命周期 在Mojo中,一个值的生命周期从变量初始化开始,直到该值最后被使用时Mojo销毁它,包括构造函数,复制构造函数,移动构造函数等。

  • 构造函数:__init__ 成员函数执行就开始执行初始化,可以重载构造函数,比如创建多个 fn __init__(inout self, ...)
  • 复制构造函数:__copy__ 成员函数执行复制新的实例,类似C++中的成员函数
  • 移动构造函数:__move__ 成员函数执行移动构造函数来实现结构体的移动,移动构造函数也返回一个新的实例,并且我们必须将其分配给一个新的变量
  • 使用样例:
代码语言:javascript
代码运行次数:0
复制
struct MyPet:
    var name: String
    var age: Int

    fn __init__(inout self, name: String, age: Int):
        self.name = name
        self.age = age

    fn __copyinit__(inout self, existing: Self):
        print("this is __copyinit__")
        self.name = existing.name
        self.age = existing.age

    fn dump(inout self): 
        print(self.name, self.age)

5、模块和包

Mojo提供了一个包装系统,允许将代码库组织和编译成可导入的文件。

(1)Mojo模块

  • 没有main函数的不能直接执行,但是可以作为模块导入
  • 导入方式:from {文件名} import {模块}
  • 导入整个模块:from {文件名}
  • 使用as创建别名,如:import mymodule as my
  • 模块需要与含有main函数的文件放到同一个目录下

(2)Mojo包 Mojo包是包含__init__.mojo文件的目录中的Mojo模块集合,通过将模块组织在一个目录中,可以一起或单独导入所有模块,目录结构可以如下:

代码语言:javascript
代码运行次数:0
复制
main.mojo
mypackage/
    __init__.mojo
    mymodule.mojo

然后可以在main.mojo这样导入:from mypackage.mymodule import {模块}

6、与Python结合

(1)导入Python模块

比如导入使用numpy,可以先导入python,如下:

代码语言:javascript
代码运行次数:0
复制
from python import Python

fn use_array() raises:
    # 这相当于Python中的`import numpy as np`
    var np = Python.import_module("numpy")

    # 现在可以像在Python中编写一样使用numpy
    var array = np.array([1, 2, 3])
    print(array)

前提条件是:

  • 导入整个Python模块,然后通过模块名称访问成员
  • 确保已经安装python的NumPy模块
  • Mojo使用Python是在安装SDK时候,会尝试查找兼容版本的Python解释器并设置Pythonsys.path来加载匹配的模块,所以使用Python的包要注意版本和路径

(2)使用Python类型

  • Mojo会在Python对象周围添加PythonObject包装器,比如:var py_list: PythonObject = [1, 2, 3, 4]
  • 可以使用Python.evaluate()创建python的类型,方便在Mojo中使用
  • 打印python类型的样例:
代码语言:javascript
代码运行次数:0
复制
fn python_types():
    try:
        from python import Python
        from python.object import PythonObject

        var value1: PythonObject = 3.7
        var value2 = Python.evaluate("10/3")
        var float_type = Python.evaluate("float")

        print(Python.type(value1))   # <class 'float'>
        print(Python.is_type(Python.type(value1), Python.type(value2)))  # True
        print(Python.is_type(Python.type(value1), float_type))           # True
        print(Python.is_type(Python.type(value1), Python.none()))        # False
    except:
        pass

7、测试代码

为了方便大家验证和测试,我提供了一些测试代码,可以直接在 playground 上运行:

代码语言:javascript
代码运行次数:0
复制
var testName: String = "aaa"

def greet2(name):
    return "Hello, " + name + "!"

fn do_math(x : Int):
    var y = 1
    y = x + y
    y = y * y
    print(y)

struct MyPair:
    var first: Int
    var second: Int
    # var third: Int

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

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

fn python_types():
    try:
        from python import Python
        from python.object import PythonObject

        var value1: PythonObject = 3.7
        var value2 = Python.evaluate("10/3")
        var float_type = Python.evaluate("float")

        print(Python.type(value1))   # <class 'float'>
        print(Python.is_type(Python.type(value1), Python.type(value2)))  # True
        print(Python.is_type(Python.type(value1), float_type))           # True
        print(Python.is_type(Python.type(value1), Python.none()))        # False
    except:
        pass

trait Quackable:
    fn quack(self): ...

@value
struct Duck(Quackable):
    fn quack(self):
        print("Quack")

@value
struct StealthCow(Quackable):
    fn quack(self):
        print("Moo!")

fn make_it_quack[T: Quackable](maybe_a_duck: T):
    maybe_a_duck.quack()

struct MyList(Sized):
    var size: Int

    fn __init__(inout self):
        self.size = 0

    fn __len__(self) -> Int:
        return self.size

struct GenericArray[T: AnyRegType]:
    var data: Pointer[T]
    var size: Int

    fn __init__(inout self, *elements: T):
        self.size = len(elements)
        self.data = Pointer[T].alloc(self.size)
        for i in range(self.size):
            self.data[i] = elements[i]

    fn __del__(owned self):
        self.data.free()

    fn __getitem__(self, i: Int) raises -> T:
        if (i < self.size):
            return self.data[i]
        else:
            raise Error("Out of bounds")

struct MyPet:
    var name: String
    var age: Int

    fn __init__(inout self, name: String, age: Int):
        self.name = name
        self.age = age

    fn __copyinit__(inout self, existing: Self):
        print("this is __copyinit__")
        self.name = existing.name
        self.age = existing.age

    fn dump(inout self): 
        print(self.name, self.age)

fn main():
    do_math(100)
    var mine = MyPair(2, 4)
    mine.dump()
    print("Hello, world!")
    python_types()
    make_it_quack(Duck())
    make_it_quack(StealthCow())
    print(len(MyList()))
    print("Parameterization: compile-time metaprogramming")
    try:
        var array = GenericArray[Int](1, 2, 3, 4)
        for i in range(array.size):
            print(array[i], sep=" ", end=" ")
    except:
        pass
    var mine1 = MyPet("Loki", 4)
    var yours = mine1
    yours.dump()

参考

(1) https://docs.modular.com/mojo/manual/basics (2) https://mojocn.org/mojo/manual (3) https://docs.modular.com/mojo/playground

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-04-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 周末程序猿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、什么是Mojo
  • 2、安装Mojo
  • 3、hello world
  • 4、Mojo 语法基础
  • 5、模块和包
  • 6、与Python结合
  • 7、测试代码
  • 参考
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档