ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## 背景 在深度学习的世界中,Vision Transformer (ViT) 模型因其在图像分类任务中的卓越表现而受到广泛关注。然而,ViT 模型通常使用 Python 编写,尤其是基于 PyTorch 框架的实现。对于 PHP 开发者来说,利用 PHP 来实现 ViT 模型可能看似不切实际,但借助`phpy`扩展,我们可以轻松地在 PHP 中调用 Python 的生态系统,从而实现这一目标。 ## ViT模型特点 ViT模型主要应用于图像分类领域。因此,其模型结构相较于传统的Transformer有以下几个特点: * 数据集的原图像被划分为多个Patch后,通过Patch Embedding将二维Patch(不考虑channel)转换为一维向量,再加上类别向量与位置向量作为模型输入。 * 模型主体的Block结构是基于Transformer的Encoder结构,但是调整了Normalization的位置,其中,最主要的结构依然是Multi-head Attention结构。 * 模型在Blocks堆叠后接全连接层,接受类别向量的输出作为输入并用于分类。通常情况下,我们将最后的全连接层称为Head,Transformer Encoder部分为backbone。 ViT模型利用Transformer模型在处理上下文语义信息的优势,将图像转换为一种`变种词向量`然后进行处理,而这种转换的意义在于,多个Patch之间本身具有空间联系,这类似于一种“空间语义”,从而获得了比较好的处理效果。 ## 什么是phpy? `phpy`是一个 PHP 扩展,允许 PHP 调用 Python 模块。这意味着我们可以在 PHP 中使用 Python 的强大功能和库,而不需要切换编程语言。这对于需要在 PHP 项目中使用深度学习模型的开发者来说,具有重要意义。 ## 代码实现 安装依赖包 ``` pip install torch ``` 安装日志 ```ts Collecting torch Downloading torch-2.4.0-cp39-cp39-manylinux1_x86_64.whl (797.2 MB) |████████████████████████████████| 797.2 MB 55 kB/s Collecting nvidia-cufft-cu12==11.0.2.54 Downloading nvidia_cufft_cu12-11.0.2.54-py3-none-manylinux1_x86_64.whl (121.6 MB) |████████████████████████████████| 121.6 MB 4.2 MB/s Collecting filelock Downloading filelock-3.15.4-py3-none-any.whl (16 kB) Collecting jinja2 Downloading jinja2-3.1.4-py3-none-any.whl (133 kB) |████████████████████████████████| 133 kB 6.7 MB/s Collecting nvidia-cuda-cupti-cu12==12.1.105 Downloading nvidia_cuda_cupti_cu12-12.1.105-py3-none-manylinux1_x86_64.whl (14.1 MB) |████████████████████████████████| 14.1 MB 922 kB/s Collecting nvidia-nvtx-cu12==12.1.105 Downloading nvidia_nvtx_cu12-12.1.105-py3-none-manylinux1_x86_64.whl (99 kB) |████████████████████████████████| 99 kB 1.1 MB/s Collecting nvidia-cudnn-cu12==9.1.0.70 Downloading nvidia_cudnn_cu12-9.1.0.70-py3-none-manylinux2014_x86_64.whl (664.8 MB) |████████████████████████████████| 664.8 MB 6.0 kB/s Collecting typing-extensions>=4.8.0 Downloading typing_extensions-4.12.2-py3-none-any.whl (37 kB) Collecting fsspec Downloading fsspec-2024.6.1-py3-none-any.whl (177 kB) |████████████████████████████████| 177 kB 4.6 MB/s Collecting nvidia-cusolver-cu12==11.4.5.107 Downloading nvidia_cusolver_cu12-11.4.5.107-py3-none-manylinux1_x86_64.whl (124.2 MB) |████████████████████████████████| 124.2 MB 1.5 MB/s Collecting nvidia-cusparse-cu12==12.1.0.106 Downloading nvidia_cusparse_cu12-12.1.0.106-py3-none-manylinux1_x86_64.whl (196.0 MB) |████████████████████████████████| 196.0 MB 3.7 MB/s Collecting nvidia-cublas-cu12==12.1.3.1 Downloading nvidia_cublas_cu12-12.1.3.1-py3-none-manylinux1_x86_64.whl (410.6 MB) |████████████████████████████████| 410.6 MB 3.0 kB/s Collecting networkx Downloading networkx-3.2.1-py3-none-any.whl (1.6 MB) |████████████████████████████████| 1.6 MB 841 kB/s Collecting triton==3.0.0 Downloading triton-3.0.0-1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (209.4 MB) |████████████████████████████████| 209.4 MB 157 kB/s Collecting sympy Downloading sympy-1.13.2-py3-none-any.whl (6.2 MB) |████████████████████████████████| 6.2 MB 1.1 MB/s Collecting nvidia-curand-cu12==10.3.2.106 Downloading nvidia_curand_cu12-10.3.2.106-py3-none-manylinux1_x86_64.whl (56.5 MB) |████████████████████████████████| 56.5 MB 279 kB/s Collecting nvidia-nccl-cu12==2.20.5 Downloading nvidia_nccl_cu12-2.20.5-py3-none-manylinux2014_x86_64.whl (176.2 MB) |████████████████████████████████| 176.2 MB 45 kB/s Collecting nvidia-cuda-nvrtc-cu12==12.1.105 Downloading nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-manylinux1_x86_64.whl (23.7 MB) |████████████████████████████████| 23.7 MB 1.8 MB/s Collecting nvidia-cuda-runtime-cu12==12.1.105 Downloading nvidia_cuda_runtime_cu12-12.1.105-py3-none-manylinux1_x86_64.whl (823 kB) |████████████████████████████████| 823 kB 2.8 MB/s Collecting nvidia-nvjitlink-cu12 Downloading nvidia_nvjitlink_cu12-12.6.68-py3-none-manylinux2014_x86_64.whl (19.7 MB) |████████████████████████████████| 19.7 MB 711 kB/s Collecting MarkupSafe>=2.0 Downloading MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (25 kB) Collecting mpmath<1.4,>=1.1.0 Downloading mpmath-1.3.0-py3-none-any.whl (536 kB) |████████████████████████████████| 536 kB 2.4 MB/s Installing collected packages: nvidia-nvjitlink-cu12, nvidia-cusparse-cu12, nvidia-cublas-cu12, mpmath, MarkupSafe, filelock, typing-extensions, triton, sympy, nvidia-nvtx-cu12, nvidia-nccl-cu12, nvidia-cusolver-cu12, nvidia-curand-cu12, nvidia-cufft-cu12, nvidia-cudnn-cu12, nvidia-cuda-runtime-cu12, nvidia-cuda-nvrtc-cu12, nvidia-cuda-cupti-cu12, networkx, jinja2, fsspec, torch Successfully installed MarkupSafe-2.1.5 filelock-3.15.4 fsspec-2024.6.1 jinja2-3.1.4 mpmath-1.3.0 networkx-3.2.1 nvidia-cublas-cu12-12.1.3.1 nvidia-cuda-cupti-cu12-12.1.105 nvidia-cuda-nvrtc-cu12-12.1.105 nvidia-cuda-runtime-cu12-12.1.105 nvidia-cudnn-cu12-9.1.0.70 nvidia-cufft-cu12-11.0.2.54 nvidia-curand-cu12-10.3.2.106 nvidia-cusolver-cu12-11.4.5.107 nvidia-cusparse-cu12-12.1.0.106 nvidia-nccl-cu12-2.20.5 nvidia-nvjitlink-cu12-12.6.68 nvidia-nvtx-cu12-12.1.105 sympy-1.13.2 torch-2.4.0 triton-3.0.0 typing-extensions-4.12.2 ``` ### PHP代码实现 让我们首先来看一下如何在 PHP 中实现 ViT 模型。以下是一个完整的 PHP 实现,利用了`phpy`扩展来调用 PyTorch: ```php <?php declare(strict_types=1); /** * Vit类定义了Vision Transformer(ViT)的结构 */ class Vit { // 定义模型的各类属性,包括嵌入大小、patch大小、patch数量,以及各种层和token private mixed $emb_size; private int $patch_size; private int $patch_count; private $conv; private $patch_emb; private $cls_token; private $pos_emb; private $tranformer_enc; private $cls_linear; private $torch; // 存储导入的torch模块 private $nn; // 存储导入的nn模块 /** * 构造函数初始化模型参数和层结构 * @param int $emb_size 嵌入的大小,默认为16 */ public function __construct($emb_size = 16) { $this->torch = PyCore::import('torch'); $this->nn = PyCore::import('torch.nn'); $this->emb_size = $emb_size; $this->patch_size = 4; $this->patch_count = intdiv(28, $this->patch_size); // 计算patch的数量 $this->conv = $this->nn->Conv2d( in_channels: 1, out_channels: pow($this->patch_size, 2), kernel_size: $this->patch_size, padding: 0, stride: $this->patch_size, ); $this->patch_emb = $this->nn->Linear(pow($this->patch_size, 2), $this->emb_size); $this->cls_token = $this->torch->randn([1, 1, $this->emb_size]); $this->pos_emb = $this->torch->randn([1, pow($this->patch_count, 2) + 1, $this->emb_size]); $encoder_layer = $this->nn->TransformerEncoderLayer($this->emb_size, 2, dim_feedforward: 2 * $this->emb_size, dropout: 0.1, activation: 'relu', layer_norm_eps: 1e-5, batch_first: true ); $this->tranformer_enc = $this->nn->TransformerEncoder($encoder_layer, 3); $this->cls_linear = $this->nn->Linear($this->emb_size, 10); } /** * 定义模型的前向传播过程 * @param mixed $x 输入的数据 * @return mixed 模型的输出 */ public function forward($x) { $operator = \PyCore::import('operator'); $x = $this->conv->forward($x); $batch_size = $x->size(0); $out_channels = $x->size(1); $height = $x->size(2); $width = $x->size(3); $x = $x->view($batch_size, $out_channels, $height * $width); $x = $x->permute([0, 2, 1]); $x = $this->patch_emb->forward($x); $cls_token = $this->cls_token->expand([$x->size(0), 1, $x->size(2)]); $x = $this->torch->cat([$cls_token, $x], 1); $x = $operator->__add__($x, $this->pos_emb); $x = $this->tranformer_enc->forward($x); return $this->cls_linear->forward($x->select(1, 0)); } } // 导入torch库,用于后续的深度学习操作 $torch = PyCore::import('torch'); // 初始化ViT模型实例,ViT是一种Vision Transformer模型 $vit = new ViT(); // 生成一个随机输入张量,形状为(5, 1, 28, 28),通常用于模拟一批图像数据 $x = $torch->rand(5, 1, 28, 28); // 通过ViT模型的forward方法对输入$x进行前向传播,得到输出$y $y = $vit->forward($x); // 打印前向传播的结果 PyCore::print($y); ``` 执行代码打印结果 ``` # php ViT.php tensor([[ 1.4124e-01, -2.2445e-01, -4.8343e-02, 1.0453e+00, 2.6407e-01, -1.0721e+00, -4.5355e-01, 9.3695e-01, 2.0814e-01, -6.9242e-01], [ 1.3197e-01, -1.7860e-01, -3.5619e-02, 1.0052e+00, 3.5701e-01, -1.0619e+00, -5.5952e-01, 8.9957e-01, 2.2079e-01, -7.3373e-01], [ 7.5269e-04, -1.9265e-01, -2.2268e-02, 9.1797e-01, 4.4237e-01, -9.6516e-01, -5.3235e-01, 1.0040e+00, 1.9907e-01, -8.6913e-01], [ 4.2739e-02, -1.3659e-01, -1.5089e-01, 9.2313e-01, 2.9609e-01, -1.0178e+00, -3.7121e-01, 9.5373e-01, 1.0967e-01, -7.0122e-01], [-1.1353e-01, -4.2927e-02, -5.9407e-02, 1.1204e+00, 1.0559e-01, -1.1278e+00, -2.8934e-01, 1.0370e+00, 2.5948e-01, -8.9551e-01]], grad_fn=<AddmmBackward0>) ``` 在上面的代码中,`phpy`的`PyCore::import()`方法使我们能够在 PHP 中导入和使用 PyTorch 模块,例如`torch`和`torch.nn`。这一点使得 PHP 可以直接调用 Python 代码,从而实现复杂的深度学习模型。 例如:在构建 ViT 模型的过程中,我们在 PHP 中使用了 Python 的`torch.nn.Conv2d`和`torch.nn.Linear`等模块,这些模块在深度学习模型的构建中起到了至关重要的作用。 ### Python代码实现 对比`vit.py`中的 Python 代码,PHP 版本的代码结构和逻辑几乎完全相同。这归功于`phpy`让我们能够在 PHP 中直接使用 Python 的语法和模块,实现了代码的高度一致性和可移植性。 ```python from torch import nn import torch class ViT(nn.Module): def __init__(self, emb_size=16): super().__init__() self.patch_size = 4 self.patch_count = 28 // self.patch_size self.conv = nn.Conv2d(in_channels=1, out_channels=self.patch_size ** 2, kernel_size=self.patch_size, padding=0, stride=self.patch_size) self.patch_emb = nn.Linear(in_features=self.patch_size ** 2, out_features=emb_size) self.cls_token = nn.Parameter(torch.rand(1, 1, emb_size)) self.pos_emb = nn.Parameter(torch.rand(1, self.patch_count ** 2 + 1, emb_size)) self.tranformer_enc = nn.TransformerEncoder( nn.TransformerEncoderLayer(d_model=emb_size, nhead=2, batch_first=True), num_layers=3) self.cls_linear = nn.Linear(in_features=emb_size, out_features=10) def forward(self, x): x = self.conv(x) x = x.view(x.size(0), x.size(1), self.patch_count ** 2) x = x.permute(0, 2, 1) x = self.patch_emb(x) cls_token = self.cls_token.expand(x.size(0), 1, x.size(2)) x = torch.cat((cls_token, x), dim=1) x = self.pos_emb + x y = self.tranformer_enc(x) return self.cls_linear(y[:, 0, :]) if __name__ == '__main__': vit = ViT() x = torch.rand(5, 1, 28, 28) y = vit(x) print(y.shape) ``` ## phpy的应用场景与意义 在实际开发中,PHP 常用于 Web 开发,但缺乏原生的深度学习支持。这使得在 PHP 项目中实现复杂的机器学习模型成为一项挑战。然而,借助`phpy`,我们可以直接调用 Python 的深度学习框架(如 PyTorch 和 TensorFlow),从而将复杂的 AI 算法无缝集成到 PHP 应用中。 这不仅扩展了 PHP 的应用范围,也为 PHP 开发者提供了更多的可能性。例如,在构建需要实时预测或复杂计算的 Web 应用时,PHP 开发者可以直接利用 Python 的丰富生态系统,而不必重新实现这些算法。 ## 结语 通过`phpy`,我们可以轻松地在 PHP 中实现 Python 的深度学习模型,如 ViT。这不仅展示了 PHP 的灵活性,也为 PHP 开发者打开了通往深度学习领域的大门。在未来,随着 AI 技术的不断发展,PHP 与 Python 的结合将为开发者带来更多创新的机会。