plainify

【译】Ilya 于 6 月 6 日在多伦多大学的毕业典礼演讲

前OpenAI联合创始人Ilya Sutskever 回到了 20 年前他拿到学位的讲台,并在这次毕业典礼发表了一场极其克制但反响热烈的演讲,有兴趣的可以查看视频的源地址:👇 Ilya Sutskever, U of T honorary degree recipient, June 6, 2025 以下是文字版内容(Translated and summarized by Qwen3) 从共同撰写开创性的研究论文到与人共同创立开发ChatGPT的研究机构,很少有人像伊利亚·苏斯克维尔(Ilya Sutskever)那样对塑造人工智能格局以及围绕该技术负责任使用进行的对话产生如此大的影响。 作为多伦多大学的一名研究生,苏斯克维尔曾是本世纪引用次数最多的学术论文之一的合著者,并且自那以后在推动一项正在改变经济、社会和人们日常生活的技术的发展和采用方面发挥了核心作用。 今天,由于他在计算机科学领域和人工智能领域的基础性工作及其全球影响力,以及他作为安全和负责任的人工智能倡导者的杰出服务,苏斯克维尔将获得多伦多大学荣誉博士学位。 大家好,很高兴能来到这里。我想感谢每一位为这次活动的组织和安排做出贡献的人,并授予我这个荣誉学位。能够获得这个荣誉学位对我来说真的非常有意义。 差不多就在20年前的今天,我在多伦多大学的这个大厅获得了我的学士学位。而现在,这已经是我在多伦多大学获得的第四个学位了。在这里度过的时光非常美好——总共10年,我完成了本科课程并学到了很多东西,之后我也成为了这里的研究生。这段时间真的很棒,我可以深入研究自己感兴趣的领域,并成为一名研究人员。 与Jeff Hinton一起学习特别让人感到荣幸。他在这所大学任教是我人生中的一大幸事。我对这所大学充满了感激之情。我觉得没有比这更好的方式来完成教育、成熟成长并成为一名科学家了。 当我还是这里的学生时,多伦多大学在AI研究方面是全球领先的,这里产生了最具革命性的想法和最激动人心的工作。我很幸运能够在研究生阶段就对这些工作有所贡献。 那是一段很久以前的事了。 我知道在一个毕业典礼致辞中,应该给出一些明智的建议。我会分享一点,但不会太多,因为今天的讲话会有些不同。 我想分享一种有助于一切变得更简单的思维方式:接受现实如其所是,不要沉溺于过去的遗憾,专注于改善现状。之所以这么说是因为这种心态很难培养起来。人们很容易陷入思考过去做的错误决定或不走运的事情上,而花时间在这些事情上是无益的。相反,更佳的做法是说:“好吧,事情就是这样,接下来最好的一步是什么?” 我发现每当我自己采用这种心态时,所有的事情都会变得更好。但这很难,这是一个与自己的情绪不断斗争的过程。这就是为什么我要提到它,也许你们中的一些人会发现它有用。这是给你们的一个提醒,也是给我自己的一个提醒。 但是除了这一点之外,这次讲话不会是最传统的毕业典礼致辞,因为我们生活在一个不同寻常的时代——也许是历史上最不同寻常的时代之一。 原因是人工智能(AI)。 据我所知,如今的AI已经极大地改变了成为学生的意义。我认为这是真实的。但是,AI的影响远不止于此,它还影响着我们所做的工作类型以及我们的职业生涯如何发展。 目前,AI正在以未知且不可预测的方式改变事物。某些领域可能会比其他领域更早感受到其影响。你可以在推特上看到AI现在能做的事情,然后你可能会想:哪些技能仍然是有用的?哪些技能可能会变得不再那么重要? 当前的挑战在于理解AI将如何影响我们的工作和职业。然而,AI真正的挑战在于它是前所未有的极端变化——未来将会与今天看起来大相径庭。 我们都已经见识过AI了——我们都曾经跟一台计算机对话,它也回应了我们。在过去,计算机并不会这样做,但现在它们做到了。它们理解我们的话语,用声音回答我们,还能编写代码——这一切都相当惊人。不过,AI还有很多事情做不到,它还有许多需要追赶的地方。 即便如此,它已经足够引人注目,让我们可以想象,在几年后——可能是三年,五年,十年,具体数字难以预测——AI会继续进步,而且可能比我们预期的更快。 最终,AI将能够做人类能做的任何事情——无论是我能学到的东西,还是你们中的任何人能学到的知识,AI都能够做到。 我为什么这么肯定呢?因为我们都有大脑——生物计算机。如果自然界可以通过生物学创造出智能,那么电子计算机当然也能做到同样的事情。 所以想象一下这样一个未来:AI能够做我们所有的工种——不仅仅是部分,而是全部。这引发了许多重大的问题。这对工作、经济乃至人类的目的意味着什么? 更进一步地说,作为社会的一员,我们将选择如何使用AI?是为了促进经济增长,加快研发进度,推动科学技术的发展吗?如果是这样,进步的速度将会极其迅速。 这些都是极端且根本性的变化——难以想象,也难以从情感上真正接受。即使是我也在努力适应这个概念。但从逻辑上看,这种情况发生的可能性似乎非常大。 那么在这种情况下一个人应该怎么做呢? 有句话说得好:“你或许对政治不感兴趣,但政治却对你感兴趣。”对于AI而言,这句话同样适用,甚至更为贴切。 通过简单地使用AI并观察当今最先进的AI系统能做什么,我们可以开始形成一种直觉。随着AI在未来一年、两年、三年内持续改进,这种直觉将变得更加明确。 再多的文章和解释都无法替代亲眼所见的事实。尤其是对于未来的超级智能AI来说,确保它们如实反映自身情况而不是伪装成其他样子的问题将是深远的。 我把很多信息压缩在了短时间内表达出来,但关键点是:不要忽视AI。关注它能做什么。当那一刻到来时,这种认识将产生所需的能量来应对AI带来的巨大挑战。 请记住,AI提出了人类历史上最大的挑战。但克服它也将带来最大的回报。 不管你是否愿意,你的生活都将被AI深刻地影响。因此,关注它,准备好帮助解决即将出现的问题吧。 非常感谢大家!

2025-06-09 54 words 1 min
plainify

【译】数据库是如何分片的?

本文翻译自 How does database sharding work?,如有疑问,请联系译者 了解什么是数据库分片,分片如何工作的,以及一些常见的分片框架和工具。 如果你使用过 Google 或 YouTube,那么你很可能已经访问过分片数据。分片通过将数据分区存储在多个服务器上,而不是将所有内容放在一个巨大的服务器上,以实现扩展数据库的目的。这篇文章将介绍数据库分片的工作原理、思考如何给你自己的数据库分片,以及其他一些有用的、可以提供帮助的工具,尤其是针对 MySQL 和 Postgres。 分片是扩展关系数据库的重要方式 试想以下场景:本季度你第三次扩大了 MySQL 版本 RDS 的实例规模,而 CFO 刚刚在会上上花了 30 分钟来“讨论预算”。也许是时候横向扩展而不是纵向扩展了! [1] RDS 中的读取副本似乎很简单,但读取数据只是问题的一半。一个心力憔悴的开发者该怎么办? 分片——这个术语可能最初来自视频游戏——一种扩展关系数据库的方式。你可能以前看过这张表格,这张表描述的是如何通过横向扩展来帮助你处理存储在单个服务器上的用户表: user_id first_name last_name email … ZpaDr20TTD4ZL7Wma Peter Gibbons peter@initech.net … bI32htQ1PsEQioC7G Bill Lumbergh bill@initech.net … 99J3x257SGP7J4IkF Milton Waddams stapler@initech.net … 0SH0pyi9bO5RM4I03 Lawrence two@onetime.com … … … … … 并将其转换为存储在 2 个(或 1,000 个)服务器上的用户表: user_id first_name last_name email Server ZpaDr20TTD4ZL7Wma Peter Gibbons peter@initech.net Server A bI32htQ1PsEQioC7G Bill Lumbergh bill@initech.net Server B 99J3x257SGP7J4IkF Milton Waddams stapler@initech.net Server B 0SH0pyi9bO5RM4I03 Lawrence two@onetime.com Server A … … … … 但这只是一种类型的分片(行级或水平)。有多种不同的方法可以跨服务器分割数据,以最好地匹配您的业务和数据模型的工作方式。例如,垂直分片是指在架构或表级别拆分内容。稍后会详细介绍! ...

plainify

【译】如何创建一个可复用的网页爬虫

原文地址:How to Create a Reusable Web Scraper 网页爬虫是个非常有趣的玩具。不过不好玩的是,我们需要根据不同网页上的元素不断的调整自己的代码。这就是为什么我要着手实现一个更好的网页爬虫项目——通过该项目可以以最少的更改实现对新网页的爬取。 第一步是将网页爬虫按照逻辑分成每个独立的部分: 页面请求器 页面验证器 模板页面处理器 页面请求器 页面请求器的实现有一些技巧。下载网页时要考虑很多因素。你需要确保你可以随机的使用用户代理,并且不要过于频繁地从同一域中请求。 此外,停下手头的工作去分析为什么网页无法下载是一件出力不讨好的事。尤其是当你的爬虫已经在多个站点运行了好几个小时的情况下。因此,我们会处理一些请求,并将它们保存为文件。 将请求保存到文件中还有另外一个好处。你不必担心一个标签的消失会影响到你的爬虫。如果页面处理器是独立的,并且你已经完成了页面的下载,你还可以根据需要快速且频繁的对其进行处理。如果发现有另一个要抓取的数据元素怎么办?别担心。只需添加一个标签,然后在你已下载的页面上重新运行处理器即可。 以下是一些实际情况下的示例代码: import requests import pickle from random import randint from urllib.parse import urlparse def _random_ua(): ua_list = ["user agent1, user agent2", "user agent3"] random_num = randint(0, len(ua_list)) return ua_list[random_num] def _headers(): return { 'user-agent': _random_ua() } def _save_page(response): uri = urlparse(response.url) filename = uri.netloc + ".pickle" with open(filename, 'wb+') as pickle_file: pickle.dump(response, pickle_file) def download_page(url): response = requests.get(url) _save_page(request) 页面验证器 页面验证器浏览文件并释放请求。它将读取请求的状态码,如果请求代码类似于 408(超时),你可以让它重新排队下载网页。否则,验证器会将文件移动到实际的 web 抓取模块中进行处理。 你还可以收集为什么页面没有下载的数据。也许你请求页面的速度太快而被禁止了。此数据可用于调整你的页面下载器,以便它可以运行尽可能快且错误量最小。 模板页面处理器 终于到这里了。我们要做的第一步是创建数据模型。让我们从 URL 开始,对于每个不同的站点/路径,可能都有不同的提取数据的方法。我们从一个字典开始,就像这样: models = { 'finance.yahoo.com':{}, 'news.yahoo.com'{}, 'bloomberg.com':{} } 在我们的用例中,我们想要提取这些网站的 article 内容。要做到这一点,我们需要创建一个选择器,用于包含所有数据的最小外部元素。举个例子,下面是 finance.yahoo.com 的示例页面: Webpage Sample <div> <a>some link</a> <p>some content</p> <article class="canvas-body"> <h1>Heading</h1> <p>article paragraph 1</p> <p class="ad">Ad Link</p> <p>article paragraph 2</p> <li>list element</li> <li> <a>unrelated link</a> </li> </article> </div> 在上面的代码段中,我们希望定位 article 元素。因此,我们将使用 article 标签和 class 作为标识符,因为这是包含 article 内容的最小元素。 ...

plainify

【译】一种有关艺术风格迁移的神经网络算法

在艺术领域, 尤其是绘画创作上, 人们已经掌握了一种可以创造独一无二视觉体验的能力, 那就是通过将一张图片的内容和风格之间构成某种复杂的关系。 到目前为止, 该过程的算法基础是未知的, 并且不存在具有类似能力的人工系统。 然而, 受到一种名为深度神经网络的视觉模型的启发, 在视觉感知的其他关键领域, 例如物体和人脸识别, 仿生学的效果已经可以接近人类的表现。 这里我们将会介绍一个基于深度神经网络的人工系统, 它可以生成具有高感知品质的艺术图片。 该系统使用神经表示来分离和重组任意图像的内容和风格, 提供了一种创建艺术图像的神经算法。 而且, 按照要去表现最优的人工神经网络和生物视觉中找到相同. 我们的工作提供了人类是怎样创作和认知艺术图像的算法理解。 此外, 鉴于性能优化的人工神经网络与生物视觉之间惊人的相似性, 我们的工作为算法理解人类如何创造和感知艺术形象提供了一条前进的道路。 处理图像任务最有效的深度神经网络是卷积神经网络。 卷积神经网络由小型计算单元层组成, 以前馈方式分层处理视觉信息(图 1)。 每层单元可以理解为图像过滤器的集合(a collection of image filters), 每个图像过滤器从输入图像中提取特定特征。 因此, 一个给定层的输出包括所谓的特征映射(feature maps): 它们是对输入的图像进行不同类型的过滤得到的。 当卷积神经网络被训练用于物体识别时, 会生成一个图像的表征(representations) , 随着处理层级的上升, 物体的信息越来越明确。 因此, 随着神经网络中的层级一级一级地被处理, 输入的图像会被转换成一种表征, 与图片的像素细节相比, 这种表征会越来越关注图片的实际内容。 通过对某一层的提取出来的 feaure map 的重塑, 我们可以直接看到该层包含的图片信息。 层级越高, 那么获取的图像中物体内容就越高质量, 并且没有确切的像素值的约束(层级越高, 像素丢失越多)。 相反, 在低层级中重塑的话, 其实像素丢失地很少。 所以我们参考的是神经网络高层的特征, 用它来作为图片内容的表征。 为了获取输入图像的风格表征, 我们用一个特征空间去捕获纹理的信息。 这个特征空间建立在每层神经网络的过滤响应之上(也就是上面提到的 feature map)。 在 feature map 的空间范围上(也就是同一层上的 feature map), 过滤响应各有不同(feature map 关注的特征不同), 而这个特征空间就是由这些差异构成。 通过对每一层 featute map 两两求相关性, 我们会获得一个静态的, 多尺度的图像表征, 这也就捕获到了图像的纹理信息, 但这纹理信息并非全局的。 ...

【译】Effective TensorFlow Chapter13——在TensorFlow中利用learn API构建神经网络框架

本文翻译自: 《Building a neural network training framework with learn API》, 如有侵权请联系删除, 仅限于学术交流, 请勿商用。 如有谬误, 请联系指出。 为了简单起见, 在之前的大多数示例中, 我们都是手动创建一个会话(session), 并不关心保存和加载检查点, 但在实践中通常不是这样做的。 在这我推荐你使用 learn API 来进行会话管理和日志记录(session management and logging)。 我们使用 TensorFlow 提供了一个简单而实用的框架来训练神经网络。 在这一节中, 我们将解释这个框架是如何工作的。 当利用神经网络训练模型进行实验时, 通常需要分割训练集和测试集。 你需要利用训练集训练你的模型, 并在测试集中计算一些指标来评估模型的好坏。 你还需要将模型参数存储为一个检查点(checkpoint), 因为你需要可以随时停止并重启训练过程。 TensorFlow 的 learn API 旨在简化这项工作, 使我们能够专注于开发实际模型。 使用 tf.learn API 的最简单的方式是直接使用 tf.Estimator 对象。 你需要定义一个模型函数, 该模型函数包含一个损失函数(loss function)、 一个训练操作(train op)、 一个或一组预测, 以及一组可选的用于评估的度量操作: import tensorflow as tf def model_fn(features, labels, mode, params): predictions = ... loss = ... train_op = ... metric_ops = ... return tf.estimator.EstimatorSpec( mode=mode, predictions=predictions, loss=loss, train_op=train_op, eval_metric_ops=metric_ops) params = ... run_config = tf.contrib.learn.RunConfig(model_dir=FLAGS.output_dir) estimator = tf.estimator.Estimator( model_fn=model_fn, config=run_config, params=params) 要训练模型, 你只需调用 Estimator.train() 函数, 同时提供一个输入函数来读取数据即可: ...

【译】Effective TensorFlow Chapter12——TensorFlow中的数值稳定性

本文翻译自: 《Numerical stability in TensorFlow》, 如有侵权请联系删除, 仅限于学术交流, 请勿商用。 如有谬误, 请联系指出。 当使用任何数值计算库(如 NumPy 或 TensorFlow)时, 值得注意的是, 编写出正确的数学计算代码对于计算出正确结果并不是必须的。 你同样需要确保整个计算过程是稳定的。 让我们从一个例子入手。 小学的时候我们就知道, 对于任意一个非 0 的数 x, 都有 x*y/y=x 。 但是让我们在实践中看看是否如此: import numpy as np x = np.float32(1) y = np.float32(1e-50) # y would be stored as zero z = x * y / y print(z) # prints nan 错误的原因是: y 是 float32 类型的数字, 所能表示的数值太小。 当 y 太大时会出现类似的问题: y = np.float32(1e39) # y would be stored as inf z = x * y / y print(z) # prints 0 float32 类型可以表示的最小正值是 1.4013e-45, 任何低于该值的数都将存储为零。 此外, 任何超过 3.40282e + 38 的数都将存储为 inf。 ...

【译】Effective TensorFlow Chapter11——在TensorFlow中调试模型

本文翻译自: 《Debugging TensorFlow models》, 如有侵权请联系删除, 仅限于学术交流, 请勿商用。 如有谬误, 请联系指出。 与常规 python 代码相比, TensorFlow 的符号特性使的 TensorFlow 的代码调试变得相对困难。 这里我介绍一些 TensorFlow 附带的工具, 使调试更容易。 使用 TensorFlow 时最常见的错误可能是传递形状错误的张量。 许多 TensorFlow 操作可以在不同秩(rank)和形状(shape)的张量上操作。 这在使用 API 时很方便, 但在出现问题时可能会导致额外的麻烦。 例如, 考虑下面这个 tf.matmul 操作, 它可以使两个矩阵相乘: a = tf.random_uniform([2, 3]) b = tf.random_uniform([3, 4]) c = tf.matmul(a, b) # c is a tensor of shape [2, 4] 但是下面这个函数也可以实现矩阵乘法: a = tf.random_uniform([10, 2, 3]) b = tf.random_uniform([10, 3, 4]) tf.matmul(a, b) # c is a tensor of shape [10, 2, 4] 下面是我们之前在广播部分谈到的一个支持广播的添加操作的例子: a = tf.constant([ [1.], [2.] ]) b = tf.constant([1., 2.]) c = a + b# c is a tensor of shape[2, 2] 使用 tf.assert * 操作验证您的张量 ...

【译】Effective TensorFlow Chapter10——在TensorFlow中利用多GPU处理并行数据

本文翻译自: 《Multi-GPU processing with data parallelism》, 如有侵权请联系删除, 仅限于学术交流, 请勿商用。 如有谬误, 请联系指出。 如果你使用类似 C++这样的语言在单核 CPU 上编写你的软件, 为使其能够在多个 GPU 上并行运行, 你可能需要从头开始重写你的软件。 但是在 TensorFlow 中并非如此。 由于其符号性质, tensorflow 可以隐藏所有这些复杂的过程, 使你无需在多个 CPU 和 GPU 上扩展程序。 让我们从在 CPU 上添加两个向量开始: import tensorflow as tf with tf.device(tf.DeviceSpec(device_type="CPU", device_index=0)): a = tf.random_uniform([1000, 100]) b = tf.random_uniform([1000, 100]) c = a + b tf.Session().run(c) 同样的事情在 GPU 上也可以简单地完成: with tf.device(tf.DeviceSpec(device_type="GPU", device_index=0)): a = tf.random_uniform([1000, 100]) b = tf.random_uniform([1000, 100]) c = a + b 但是, 如果我们有两个 GPU 并希望同时使用它们呢? 为此, 我们可以把数据分成两份, 并让每个 GPU 单独处理一个部分: split_a = tf.split(a, 2) split_b = tf.split(b, 2) split_c = [] for i in range(2): with tf.device(tf.DeviceSpec(device_type="GPU", device_index=i)): split_c.append(split_a[i] + split_b[i]) c = tf.concat(split_c, axis=0) 让我们以更一般的形式重写它, 以便我们可以用任何其他操作集替换添加: def make_parallel(fn, num_gpus, **kwargs): in_splits = {} for k, v in kwargs.items(): in_splits[k] = tf.split(v, num_gpus) out_split = [] for i in range(num_gpus): with tf.device(tf.DeviceSpec(device_type="GPU", device_index=i)): with tf.variable_scope(tf.get_variable_scope(), reuse=tf.AUTO_REUSE): out_split.append(fn(**{k : v[i] for k, v in in_splits.items()})) return tf.concat(out_split, axis=0) def model(a, b): return a + b c = make_parallel(model, 2, a=a, b=b) 你可以使用任何一个将张量作为输入并返回张量的函数来替换模型, 限定条件是输入和输出都必须在一个批次(batch)内。 值得注意的是, 我们还添加了一个变量作用域并将 reuse 属性设置为 true。 这个操作确保我们可以使用相同的变量来处理两个部分的数据。 如此操作让我们在下一个例子中变得很方便。 ...

【译】Effective TensorFlow Chapter9——使用Python ops进行原型内核和高级可视化

本文翻译自: 《Prototyping kernels and advanced visualization with Python ops》, 如有侵权请联系删除, 仅限于学术交流, 请勿商用。 如有谬误, 请联系指出。 TensorFlow 中的内核操作完全用 C ++编写, 以提高效率。 但是用 C++编写 TensorFlow 内核的话可能会非常痛苦。 因此, 在花费数小时实现属于自己的内核之前, 你也许需要先实现一个操作的原型, 尽管这样的效率会很低。 通过 tf.py_func() 你可以将任何一个 python 源代码转换为 TensorFlow 的操作。 举个例子而言, 这里有一个用 python 自己实现的 ReLU 非线性激活函数, 通过 tf.py_func() 转换为 TensorFlow 操作的例子: import numpy as np import tensorflow as tf import uuid def relu(inputs): # Define the op in python def _relu(x): return np.maximum(x, 0.) # Define the op's gradient in python def _relu_grad(x): return np.float32(x > 0) # An adapter that defines a gradient op compatible with TensorFlow def _relu_grad_op(op, grad): x = op.inputs[0] x_grad = grad * tf.py_func(_relu_grad, [x], tf.float32) return x_grad # Register the gradient with a unique id grad_name = "MyReluGrad_" + str(uuid.uuid4()) tf.RegisterGradient(grad_name)(_relu_grad_op) # Override the gradient of the custom op g = tf.get_default_graph() with g.gradient_override_map({"PyFunc": grad_name}): output = tf.py_func(_relu, [inputs], tf.float32) return output 通过 TensorFlow 的gradient checker, 你可以确认这些梯度是否计算正确: ...

【译】Effective TensorFlow Chapter8——控制流操作: 条件和循环

本文翻译自: 《Control flow operations: conditionals and loops》, 如有侵权请联系删除, 仅限于学术交流, 请勿商用。 如有谬误, 请联系指出。 当我们在构建一个复杂模型如 RNN(循环神经网络)的时候, 你可能需要通过条件和循环来控制操作流程。 在这一节, 我们介绍一些在 TensorFlow 中常用的控制流。 假设我们现在需要通过一个条件判断来决定我们是否相加还是相乘两个变量。 这个可以通过调用 tf.cond() 简单实现, 它表现出像 python 中 if...else... 相似的功能。 a = tf.constant(1) b = tf.constant(2) p = tf.constant(True) x = tf.cond(p, lambda: a + b, lambda: a * b) print(tf.Session().run(x)) 因为这个条件判断为 True, 所以这个输出应该是加法输出, 也就是输出 3。 在使用 TensorFlow 的过程中, 大部分时间你都会使用大型的张量, 并且在一个批次(a batch)中进行操作。 一个与之相关的条件操作符是 tf.where() , 它需要提供一个条件判断, 就和 tf.cond() 一样, 但是 tf.where() 将会根据这个条件判断, 在一个批次中选择输出, 如: a = tf.constant([1, 1]) b = tf.constant([2, 2]) p = tf.constant([True, False]) x = tf.where(p, a + b, a * b) print(tf.Session().run(x)) 返回的结果是 [3, 2] 。 ...