字节瓜落:“实习生破坏大模型”事件背后真相

字节瓜落

前几天,国内互联网最大的瓜,是「字节跳动实习生破坏大模型训练,造成上千万美元损失」的新闻。

作为常年走在冲浪最前线的公众号,没有第一时间跟大家"吃瓜",主要是那个消息太有倾向性,不像是真的。

alt

原消息小作文写的是这位同学,因为不满公司的资源分配(自己所在的小组被冷落),于是往商业化整个 GPU 都注入了病毒,使得 8000 多张 H100 一个多月的训练结果全是错的。

病毒原理是利用的 huggingface 的函数的漏洞实现代码注入,随机 sleep 并修改参数方向。

更魔幻的是,这小伙还潜伏在查证小组的群里,追查小组查到什么,他就改什么,上演极致攻防。

我是看到这里,才觉得剧本不对劲,明明都已经遭受冷落,怎么还混进了查证小组呢?

果然,在经过了几天自媒体炒作后,字节跳动实在坐不住了,昨天就正式针对此事进行辟谣:

alt

确实有实习生恶意干扰训练任务,但只是研究项目类的训练任务,不涉及其他大模型,那"涉及 8000 多张卡,造成上千万美元损失"的说法,自然是夸大了。

另外这事其实 8 月份已被查实,实习生也被字节辞退了,并不是小作文说的,近期发生,且"人被送进去"。

对于此事,你了解到的是什么版本?是完全没听过这事儿,还是只听过小作文的版本?

...

回归主题。

来一道简简单单算法题。

题目描述

平台:LeetCode

题号:832

给定一个二进制矩阵 A,我们想先水平翻转图像,然后反转图像并返回结果。

水平翻转图片就是将图片的每一行都进行翻转,即逆序。例如,水平翻转 [1, 1, 0] 的结果是 [0, 1, 1]。

反转图片的意思是图片中的 0 全部被 1 替换,1 全部被 0 替换。

例如,反转 [0, 1, 1] 的结果是 [1, 0, 0]。

示例 1:

输入:[[1,1,0],[1,0,1],[0,0,0]]

输出:[[1,0,0],[0,1,0],[1,1,1]]

解释:首先翻转每一行: [[0,1,1],[1,0,1],[0,0,0]];
     然后反转图片: [[1,0,0],[0,1,0],[1,1,1]]

示例 2:

输入:[[1,1,0,0],[1,0,0,1],[0,1,1,1],[1,0,1,0]]

输出:[[1,1,0,0],[0,1,1,0],[0,0,0,1],[1,0,1,0]]

解释:首先翻转每一行: [[0,0,1,1],[1,0,0,1],[1,1,1,0],[0,1,0,1]];
     然后反转图片: [[1,1,0,0],[0,1,1,0],[0,0,0,1],[1,0,1,0]]

提示:

双指针

对于每行而言,我们都需要对其进行「翻转」和「反转」。

这两步可以到放到一遍循环里做:

  • 翻转部分:使用双指针进行数字交换
  • 反转部分:将数字存储进目标位置前,使用「异或」对 0 1 进行翻转

当前有一些「小细节」需要注意:

  1. 题目要求我们对参数图像进行翻转,并返回新图像。因此我们不能对输入直接进行修改,而要先进行拷贝再处理
  2. 由于我们将「翻转」和「反转」合成了一步,因此对于「奇数」图像,需要对中间一列进行特殊处理:仅「反转」

对于 Java 的基本类型拷贝,有三种方式进行拷贝:

  1. System.arraycopy() : 底层的数组拷贝接口,具体实现与操作系统相关,调用的是系统本地方法。需要自己创建好目标数组进行传入,可指定拷贝长度,实现局部拷贝。
  2. Arrays.copyOf() : 基于 System.arraycopy() 封装的接口,省去了自己目标数组这一步。但无法实现局部拷贝。
  3. clone() : Object 的方法。会调用每个数组成员的 clone() 方法进行拷贝。因此对于一维数组而言,可以直接使用 clone() 得到「深拷贝数组」,而对于多维数组而言,得到的是「浅拷贝数组」。

Java 代码(P1):

class Solution {
    public int[][] flipAndInvertImage(int[][] a) {
        int n = a.length;
        int[][] ans = new int[n][n];
        for (int i = 0; i < n; i++) {
            // ans[i] = a[i].clone(); 
            // ans[i] = Arrays.copyOf(a[i], n); 
            System.arraycopy(a[i], 0, ans[i], 0, n); 
            int l = 0, r = n - 1;
            while (l < r) {
                int c = ans[i][r];
                ans[i][r--] = ans[i][l] ^ 1;
                ans[i][l++] = c ^ 1;
            }
            if (n % 2 != 0) ans[i][r] ^= 1
        }
        return ans;
    }
}

Java 代码(P2):

class Solution {
    public int[][] flipAndInvertImage(int[][] a) {
        int n = a.length;
        int[][] ans = new int[n][n];
        // 遍历每一行进行处理
        for (int i = 0; i < n; i++) {
            // 对每一行进行拷贝(共三种方式)
            // ans[i] = a[i].clone(); 
            // ans[i] = Arrays.copyOf(a[i], n); 
            System.arraycopy(a[i], 0, ans[i], 0, n); 
            // 使用「双指针」对其进行数组交换,实现「翻转」
            // 并通过「异或」进行 0 1 翻转,实现「反转」
            int l = 0, r = n - 1;
            while (l < r) {
                int c = ans[i][r];
                ans[i][r--] = ans[i][l] ^ 1;
                ans[i][l++] = c ^ 1;
            }
            // 由于「奇数」矩形的中间一列不会进入上述双指针逻辑
            // 需要对其进行单独「反转」
            if (n % 2 != 0) ans[i][r] ^= 1
        }
        return ans;
    }
}
  • 时间复杂度:
  • 空间复杂度:使用了同等大小的空间存储答案。复杂度为

补充

Q: 那么 Arrays.copyOfRange()System.arraycopy() 作用是否等同呢?

A: 不等同。

Arrays.copyOf()Arrays.copyOfRange() 都会内部创建目标数组。

前者是直接创建一个和源数组等长的数组,而后者则是根据传参 tofrom 计算出目标数组长度进行创建。

它们得到的数组都是完整包含了要拷贝内容的,都无法实现目标数组的局部拷贝功能。

例如我要拿到一个长度为 10 的数组,前面 5 个位置的内容来源于「源数组」的拷贝,后面 5 个位置我希望预留给我后面自己做操作,它们都无法满足,只有 System.arraycopy() 可以。

最后

巨划算的 LeetCode 会员优惠通道目前仍可用 ~

使用福利优惠通道 leetcode.cn/premium/?promoChannel=acoier,年度会员 有效期额外增加两个月,季度会员 有效期额外增加两周,更有超大额专属 🧧 和实物 🎁 福利每月发放。

我是宫水三叶,每天都会分享算法知识,并和大家聊聊近期的所见所闻

欢迎关注,明天见。

更多更全更热门的「笔试/面试」相关资料可访问排版精美的 合集新基地 🎉🎉

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值