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] 。 ...

【译】Effective TensorFlow Chapter7——理解执行顺序和控制依赖

本文翻译自: 《Understanding order of execution and control dependencies》, 如有侵权请联系删除, 仅限于学术交流, 请勿商用。 如有谬误, 请联系指出。 正如我们刚开始提到的, TensorFlow 不会立刻运行定义了的操作, 而是在计算图中创造一个相关的节点, 这个节点可以用 Session.run() 进行执行。 这个使得 TensorFlow 可以在运行时进行优化, 以此确定最佳执行顺序, 并且在运算中剔除一些不需要使用的节点。 如果你只是在计算图中使用 tf.Tensors , 你就不需要担心依赖问题, 但是你更可能会使用 tf.Variable() , 这个操作使得问题变得更加困难。 我的建议是如果张量不能满足这个工作需求, 那么仅仅使用 Variables 就足够了。 这个可能不够直观, 我们不妨先观察一个例子: import tensorflow as tf a = tf.constant(1) b = tf.constant(2) a = a + b tf.Session().run(a) 正如我们期待的那样, “a”的计算结果是 3。 注意下, 我们创建了 3 个张量, 其中包含两个常数张量和一个储存加法结果的张量。 务必注意我们不能重写一个张量的值, 如果我们想要改变张量的值, 我们就必须要创建一个新的张量, 就像我们刚才做的那样。 **小提示: **如果你没有定义一个新的计算图, TF 将会自动地为你构建一个默认的计算图。 你可以使用 tf.get_default_graph() 去获得一个计算图的句柄(handle), 然后, 你就可以查看这个计算图了。 比如, 打印这个计算图的所有张量: print(tf.contrib.graph_editor.get_tensors(tf.get_default_graph())) 和 tensors 不同的是, 变量 Variables 可以更新, 所以让我们用变量去实现我们刚才的需求: ...