通过SketchRNN、PCA和t-SNE从Google QuickDraw数据集中显示矢量图的潜在空间|附源码

首发地址:

更多深度文章,请关注:https://yq.aliyun.com/cloud

本文是作者最近发布的Google QuickDraw数据集一系列笔记中的第三部分,使用的最近发布的SketchRNN模型。下面介绍QuickDraw数据集及SketchRNN模型。
        QuickDraw数据集是由世界各地1500多万人参与的“快速绘画” AI实验后收集数百万幅图画建成,要求参与者在20秒内绘制出属于某个类(例如“猫”)的图像。如下图所示,选择一个类别,可以看见数据库中该类所有的形状。

当然,如果数据集中没有和你想象一样的形状,你也可以帮助向该数据库中增添一些涂鸦,进行个人绘画表演。

 

        SketchRNN是基于上述数据集训练的生成模型,被训练成能够生成矢量图,它巧妙地集合了机器学习中最近开发的许多最新的工具和技术,例如Variational AutoencodersHyperLSTMs(一个用于LSTM的HyperNetwork)、自回归模型 ,Layer NormalizationRecurrent DropoutAdam optimizer等。

        SketchRNN系统是由谷歌探究AI能否创作艺术的新项目的一部分,类似于教AI去绘画,另外不仅仅是让人工智能学习如何画画,还要能够“用类似于人类的方式概括归纳抽象的概念”,比如去画“猪”的广义概念,而不是画特定的动物,这显然不是一件简单的事情(下图 SketchRNN系统画的“猪”)。

该模型能够将你的灵魂画作对应成实际的物品,当然,如果画作太过于抽象,暂时是无法识别或者是识别错误,毕竟它还没有学会读心术(自己画的自行车,系统无法识别)。



       本文代码舍弃了那些旨在解释或演示的代码块,只保留了运行实验所需的代码。“潜在空间中的主成分分析 ”部分的所有内容是直接从以前的博客中摘取。随意跳过该部分,因为接下来是真正有趣的分析。这里是第一第二博客的链接,之前所讲述的一切都是一些实用功能,以便于现在的可视化分析。

        本文是笔记代码的结合,作者已经做出了风格以及其它一些细微的改变,以确保Python3能向前兼容。

  • 1. 本文有点令人误解,这是因为本文主要是探索Aaron Koblin羊市场 (aaron-sheep)数据集,这是一个较小的轻量级数据集,以及一个手册,演示了在这个数据集上已经预先训练好的各种模型。由于该数据集模式与QuickDraw数据集相同,因此在此数据集上执行的实验也不失一般性。
  • 2. Magenta目前只支持Python 2版本。

接下来都是实验的所需的python代码,其中[num]是表示该github工程文件的代码块:
在代码块[2]中:


%matplotlib inline
%config InlineBackend.figure_format = 'svg'
%load_ext autoreload
%autoreload 2

在代码块[3]中


import matplotlib.pyplot as plt
import matplotlib.patches as patches

import numpy as np
import tensorflow as tf

from matplotlib.animation import FuncAnimation
from matplotlib.path import Path
from matplotlib import rc

from sklearn.decomposition import PCA
from sklearn.manifold import TSNE

from itertools import product
from six.moves import map, zip

在代码块[5]中:


from magenta.models.sketch_rnn.sketch_rnn_train import \
    (load_env,
     load_checkpoint,
     reset_graph,
     download_pretrained_models,
     PRETRAINED_MODELS_URL)
from magenta.models.sketch_rnn.model import Model, sample
from magenta.models.sketch_rnn.utils import (lerp,
                                             slerp,
                                             get_bounds,
                                             to_big_strokes,
                                             to_normal_strokes)

在代码块[6]中:


# For inine display of animation
# equivalent to rcParams['animation.html'] = 'html5'
rc('animation', html='html5')

在代码块[5]中:


# set numpy output to something sensible
np.set_printoptions(precision=8,
                    edgeitems=6,
                    linewidth=200,
                    suppress=True)

在代码块[6]中:


tf.logging.info("TensorFlow Version: {}".format(tf.__version__))
INFO:tensorflow:TensorFlow版本:1.1.0

获得预训练的模型和数据

在代码块[7]中:


DATA_DIR = ('http://github.com/hardmaru/sketch-rnn-datasets/'
            'raw/master/aaron_sheep/')
MODELS_ROOT_DIR = '/tmp/sketch_rnn/models'

在代码块[8]中:


DATA_DIR

输出[8]:

'http://github.com/hardmaru/sketch-rnn-datasets/raw/master/aaron_sheep/'

在代码块[9]中:

PRETRAINED_MODELS_URL

输出[9]:

'http://download.magenta.tensorflow.org/models/sketch_rnn.zip'

在代码块[10]中:

download_pretrained_models(
    models_root_dir=MODELS_ROOT_DIR,
    pretrained_models_url=PRETRAINED_MODELS_URL)

接下来让我们看看aaron_sheep现在数据集训练的规范化层模型。

在代码块[11]中:


MODEL_DIR = MODELS_ROOT_DIR + '/aaron_sheep/layer_norm'

在代码块[12]中:


(train_set,
 valid_set,
 test_set,
 hps_model,
 eval_hps_model,
 sample_hps_model) = load_env(DATA_DIR, MODEL_DIR)

INFO:tensorflow:Downloading http://github.com/hardmaru/sketch-rnn-datasets/raw/master/aaron_sheep/aaron_sheep.npz
INFO:tensorflow:Loaded 7400/300/300 from aaron_sheep.npz
INFO:tensorflow:Dataset combined: 8000 (7400/300/300), avg len 125
INFO:tensorflow:model_params.max_seq_len 250.
total images <= max_seq_len is 7400
total images <= max_seq_len is 300
total images <= max_seq_len is 300
INFO:tensorflow:normalizing_scale_factor 18.5198.

在代码块[13]中:


class SketchPath(Path):

    def __init__(self, data, factor=.2, *args, **kwargs):

        vertices = np.cumsum(data[::, :-1], axis=0) / factor
        codes = np.roll(self.to_code(data[::,-1].astype(int)),
                        shift=1)
        codes[0] = Path.MOVETO

        super(SketchPath, self).__init__(vertices,
                                         codes,
                                         *args,
                                         **kwargs)

    @staticmethod
    def to_code(cmd):
        # if cmd == 0, the code is LINETO
        # if cmd == 1, the code is MOVETO (which is LINETO - 1)
        return Path.LINETO - cmd

在代码块[14]中:


def draw(sketch_data, factor=.2, pad=(10, 10), ax=None):

    if ax is None:
        ax = plt.gca()

    x_pad, y_pad = pad

    x_pad //= 2
    y_pad //= 2

    x_min, x_max, y_min, y_max = get_bounds(data=sketch_data,
                                            factor=factor)

    ax.set_xlim(x_min-x_pad, x_max+x_pad)
    ax.set_ylim(y_max+y_pad, y_min-y_pad)

    sketch = SketchPath(sketch_data)

    patch = patches.PathPatch(sketch, facecolor='none')
    ax.add_patch(patch)

加载预先训练好的模型

在代码块[15]中:


# construct the sketch-rnn model here:
reset_graph()
model = Model(hps_model)
eval_model = Model(eval_hps_model, reuse=True)
sample_model = Model(sample_hps_model, reuse=True)

INFO:tensorflow:Model using gpu.
INFO:tensorflow:Input dropout mode = False.
INFO:tensorflow:Output dropout mode = False.
INFO:tensorflow:Recurrent dropout mode = True.
INFO:tensorflow:Model using gpu.
INFO:tensorflow:Input dropout mode = False.
INFO:tensorflow:Output dropout mode = False.
INFO:tensorflow:Recurrent dropout mode = False.
INFO:tensorflow:Model using gpu.
INFO:tensorflow:Input dropout mode = False.
INFO:tensorflow:Output dropout mode = False.
INFO:tensorflow:Recurrent dropout mode = False.

在代码块[16]中:


sess = tf.InteractiveSession()
sess.run(tf.global_variables_initializer())

在代码块[17]中:


# loads the weights from checkpoint into our model
load_checkpoint(sess=sess, checkpoint_path=MODEL_DIR)

INFO:tensorflow:Loading model /tmp/sketch_rnn/models/aaron_sheep/layer_norm/vector.
INFO:tensorflow:Restoring parameters from /tmp/sketch_rnn/models/aaron_sheep/layer_norm/vector

在代码块[18]中:


def encode(input_strokes):
    strokes = to_big_strokes(input_strokes).tolist()
    strokes.insert(0, [0, 0, 1, 0, 0])
    seq_len = [len(input_strokes)]
    z = sess.run(eval_model.batch_z,
                 feed_dict={
                    eval_model.input_data: [strokes],
                    eval_model.sequence_lengths: seq_len})[0]
    return z

在代码块[19]中:


def decode(z_input=None, temperature=.1, factor=.2):
    z = None
    if z_input is not None:
        z = [z_input]
    sample_strokes, m = sample(
        sess,
        sample_model,
        seq_len=eval_model.hps.max_seq_len,
        temperature=temperature, z=z)
    return to_normal_strokes(sample_strokes)

用主成分分析探索潜在空间

PCA是一种降维方法,是通过线性变换将原始数据变换为一组各维度线性无关的表示,可用于提取数据的主要特征分量,常用于高维数据的降维。

下面,我们将测试集中的所有草图编码为学习到的128维潜在空间中的表示。

在代码块[20]中:


Z = np.vstack(map(encode, test_set.strokes))
Z.shape

输出[20]:

(300,128) 注:128代表128维

然后,找到潜在空间中编码数据中代表最大方差方向的两个主轴。 

在代码块[22]中:

pca = PCA(n_components=2)

在代码块[23]中:

pca.fit(Z)

输出[23]:

PCA(copy = True,iterated_power ='auto',n_components = 2,random_state = None,svd_solver ='auto',tol = 0.0,whiten = False) 

这两个组成部分分别约占方差的2% 

在代码块[24]中:




pca.explained_variance_ratio_

输出[24]:

([0.02140247,0.02067117]) 

接下来将数据从128维的潜在空间映射为由前两个主要分量构建的二维空间 

在代码块[25]中:



Z_pca = pca.transform(Z)
Z_pca.shape

输出[25]:

(300,2) 注:2代表2维

在代码块[26]中:


fig, ax = plt.subplots()

ax.scatter(*Z_pca.T)

ax.set_xlabel('$pc_1$')
ax.set_ylabel('$pc_2$')

plt.show()

我们想在上图中通过图中的对应点可视化出原始草图,其中每个点对应于草图降维到2维的隐藏代码。然而,由于图像太密集,在没有重叠的情况下无法适应足够大的草图。因此,我们将注意力限制在包含80%数据点的较小区域,蓝色阴影矩形突出显示感兴趣的区域。 

在代码块[106]中:


((pc1_min, pc2_min),
 (pc1_max, pc2_max)) = np.percentile(Z_pca, q=[5, 95], axis=0)

在代码块[107]中:


roi_rect = patches.Rectangle(xy=(pc1_min, pc2_min),
                             width=pc1_max-pc1_min,
                             height=pc2_max-pc2_min, alpha=.4)

在代码块[108]中:


fig, ax = plt.subplots()

ax.scatter(*Z_pca.T)
ax.add_patch(roi_rect)

ax.set_xlabel('$pc_1$')
ax.set_ylabel('$pc_2$')

plt.show()

在代码块[109]中:


fig, ax = plt.subplots(figsize=(10, 10))

ax.set_xlim(pc1_min, pc1_max)
ax.set_ylim(pc2_min, pc2_max)

for i, sketch in enumerate(test_set.strokes):
    sketch_path = SketchPath(sketch, factor=7e+1)
    sketch_path.vertices[::,1] *= -1
    sketch_path.vertices += Z_pca[i]
    patch = patches.PathPatch(sketch_path, facecolor='none')
    ax.add_patch(patch)

ax.set_xlabel('$pc_1$')
ax.set_ylabel('$pc_2$')

plt.savefig("../../files/sketchrnn/aaron_sheep_pca.svg",
            format="svg", dpi=1200)

可以在这里找到SVG图像。

备注:一个更加聪明的方法涉及到使用matplotlib变换Collections API,具体是通过实例化带有关键参数oofets的PathCollection。

PCA投影中的线性插值
在先前定义的矩形区域生成100个均匀间隔的网格,下图网格中的点以橙色表示,覆盖在测试数据点的顶部。 

在代码块[35]中:


pc1 = lerp(pc1_min, pc1_max, np.linspace(0, 1, 10))

在代码块[36]中:


pc2 = lerp(pc2_min, pc2_max, np.linspace(0, 1, 10))

在代码块[37]中:


pc1_mesh, pc2_mesh = np.meshgrid(pc1, pc2)

在代码块[38]中:


fig, ax = plt.subplots()

ax.set_xlim(pc1_min-.5, pc1_max+.5)
ax.set_ylim(pc2_min-.5, pc2_max+.5)

ax.scatter(*Z_pca.T)
ax.scatter(pc1_mesh, pc2_mesh)

ax.set_xlabel('$pc_1$')
ax.set_ylabel('$pc_2$')

plt.show()

接下来,通过应用PCA的逆变换来将网格上的100个点投影到原始的128维潜在空间。 

在代码块[39]中:


np.dstack((pc1_mesh, pc2_mesh)).shape

输出[39]:

(10,10,2) 

在代码块[40]中:


z_grid = np.apply_along_axis(pca.inverse_transform,
                             arr=np.dstack((pc1_mesh, pc2_mesh)),
                             axis=2)
z_grid.shape

输出[40]:

(10,10,128) 

然后,使用这些隐藏代码及译码器重建相应的草图,并观察草图如何在所关注的矩形区域范围之间转换,特别是草图从左到右、从上到下的转换,因为这些是潜在表示中最大差异的方向。首先,以较低的温度设置τ=0.1运行译码器以最小化样本的随机性。 

在代码块[94]中:


fig, ax_arr = plt.subplots(nrows=10,
                           ncols=10,
                           figsize=(8, 8),
                           subplot_kw=dict(xticks=[],
                                           yticks=[],
                                           frame_on=False))
fig.tight_layout()

for i, ax_row in enumerate(ax_arr):
    for j, ax in enumerate(ax_row):
        draw(decode(z_grid[-i-1,j], temperature=.1), ax=ax)
        ax.axis('off')

plt.show()

可以从上图中观察到一些有趣的变换和模式。在右下角,可以看到一群类似的修剪过或者无修饰的羊;当向左上方移动时,会开始看到一些羊毛、粗糙的圆形涂鸦的羊;沿着中间部分,可以看到最逼真的羊;在左上角,可以看到一些抽象的草图。

在代码块[95]中:


fig, ax_arr = plt.subplots(nrows=10,
                           ncols=10,
                           figsize=(8, 8),
                           subplot_kw=dict(xticks=[],
                                           yticks=[],
                                           frame_on=False))
fig.tight_layout()

for i, ax_row in enumerate(ax_arr):
    for j, ax in enumerate(ax_row):
        draw(decode(z_grid[-i-1,j], temperature=.6), ax=ax)
        ax.axis('off')

plt.show()

特征羊分解
本文将草图学习的潜在代表主要组成部分称为特征羊。

使用译码器,可以可视化前2个特征羊的草图表示,这些特征羊是将潜在表示转换为二维子空间中的正交权重矢量。通过将它们视为隐藏代码,并将其重构建为草图,我们能够提炼出一些有意义的解释。 

在代码块[48]中:


z_pc1, z_pc2 = pca.components_

在代码块[49]中:


pca.explained_variance_ratio_

输出[49]:

([0.02140247,0.02067117]) 

在代码块[50]中:

pca.explained_variance_

输出[50]:

([2.51394317,2.42804484])

我们从τ=.01...1.0增加温度并绘制特征羊的重建草图,每个温度设置采集5个样品。 

在代码块[58]中:

fig, ax_arr = plt.subplots(nrows=5,
                           ncols=10,
                           figsize=(8, 4),
                           subplot_kw=dict(xticks=[],
                                           yticks=[],
                                           frame_on=False))
fig.tight_layout()

for row_num, ax_row in enumerate(ax_arr):
    for col_num, ax in enumerate(ax_row):
        t = (col_num + 1) / 10.
        draw(decode(z_pc1, temperature=t), ax=ax)

        if row_num + 1 == len(ax_arr):
            ax.set_xlabel(r'$\tau={}$'.format(t))

plt.show()

在代码块[63]中:

fig, ax_arr = plt.subplots(nrows=5,
                           ncols=10,
                           figsize=(8, 4),
                           subplot_kw=dict(xticks=[],
                                           yticks=[],
                                           frame_on=False))
fig.tight_layout()

for row_num, ax_row in enumerate(ax_arr):
    for col_num, ax in enumerate(ax_row):
        t = (col_num + 1) / 10.
        draw(decode(z_pc2, temperature=t), ax=ax)

        if row_num + 1 == len(ax_arr):
            ax.set_xlabel(r'$\tau={}$'.format(t))

plt.show()

对于第一特征羊,在τ=0.1,主要看到一个圆形的黑色头发、有两条长的圆形腿和一些尾巴。沿着轴线方向可以看到,羊的头部和腿部结构会发生变化,这占据了草图的大部分差异。

现在看看第二特征羊,集中τ值较低时生成的样品,可以看到一些粗略潦草的圆圈代表羊的身体、3-4个松散连接的腿和一个小圆头。从上到下的观察,可以发现,与第一特征不同的是这似乎是沿着羊身体结构变化的方向。

t-SNE可视化
     t分布随机相邻嵌入(t-SNE)是一种常用的非线性降维技术,通常用于可视化高维数据。它是几种嵌入方法之一,其目的是将数据点嵌入到较低维空间中,以保持原始高维空间中的点对点的距离,一般适用于二维空间的可视化。

     特别地,t-SNE通常用于深度学习,以检查和可视化深层神经网络学到的内容。例如,在图像分类问题中,可以将卷积神经网络视为一系列变换,逐渐将图像转换为表示,使得类可以更容易地被线性分类器区分。因此,可以将分类器前的最后一层输出作为“代码”,然后使用t-SNE在二维中嵌入和可视化图像的代码表示。

在这里,将每个矢量绘图的128维隐藏代码嵌入到二维中,并将其在该二维子空间中进行可视化。 

在代码块[97]中:

tsne = TSNE(n_components=2, n_iter=5000)

在代码块[98]中:

Z_tsne = tsne.fit_transform(Z)

在代码块[99]中:

fig, ax = plt.subplots()

ax.scatter(*Z_tsne.T)

ax.set_xlabel('$c_1$')
ax.set_ylabel('$c_2$')

plt.show()

在代码块[100]中:

tsne.kl_divergence_

输出[100]:

2.2818214893341064 

像以前一样,定义一个矩形区域 

在代码块[101]中:

((c1_min, c2_min),
 (c1_max, c2_max)) = np.percentile(Z_tsne, q=[5, 95], axis=0)

在代码块[102]中:

roi_rect = patches.Rectangle(xy=(c1_min, c2_min),
                             width=c1_max-c1_min,
                             height=c2_max-c2_min, alpha=.4)

在代码块[103]中:

fig, ax = plt.subplots()

ax.scatter(*Z_tsne.T)
ax.add_patch(roi_rect)

ax.set_xlabel('$c_1$')
ax.set_ylabel('$c_2$')

plt.show()

在代码块[104]中:

fig, ax = plt.subplots(figsize=(10, 10))

ax.set_xlim(c1_min, c1_max)
ax.set_ylim(c2_min, c2_max)

for i, sketch in enumerate(test_set.strokes):
    sketch_path = SketchPath(sketch, factor=2.)
    sketch_path.vertices[::,1] *= -1
    sketch_path.vertices += Z_tsne[i]
    patch = patches.PathPatch(sketch_path, facecolor='none')
    ax.add_patch(patch)

ax.axis('off')

plt.savefig("../../files/sketchrnn/aaron_sheep_tsne.svg",
            format="svg")

完整的SVG图片可以在此获得。虽然这产生了很好的结果,但作者认为如果可视化在一个具有多类的更大数据集上会更有说服力。通过这种方式,可以看到t-SNE有效地形成了对不同类的聚类图,并突出显示了每个集群中的变化。

如果是RGB光栅图,使用像t-SNE这样的技术会获得很奇特的结果(比如多个头的小狗等)。然而,相似之处往往是表面的,主要是基于色度、亮度等方面。当嵌入代码表示时,相似性变得更加抽象,并且往往是基于类和语义。此外,这也允许我们能够检测出神经网络形成了什么样的相似性概念。

在另一方面,矢量图是由连续的笔画组成,能被表示成笛卡尔平面上的偏移量序列。一般来说,任意长度序列之间的相似性度量并没有得到很好地定义。因此,不能直接在矢量图上应用降维技术。

使用变形的递归神经网络,比如SketchRNN,可以将原始图转换为潜在空间中丰富的表示,这样做可以使得我们运用强大的技术如t-SNE去组织并可视化这些表示。另外利用相似性能够提炼更多的语义和抽象的概念。

本文的工作是受到其它一些优秀的文章和工作的启发,如下所示:

作者信息

Louis Tiao:计算机科学和数学的研究者,研究领域集中于算法设计与分析、计算机科学理论、人工智能和机器学习。

Linkedin:http://www.linkedin.com/in/ltiao/?ppe=1

Github:https://github.com/scikit-learn/scikit-learn

本文由北邮@爱可可-爱生活老师推荐,阿里云组织翻译。

文章原标题《Visualizing the Latent Space of Vector Drawings from the Google QuickDraw Dataset with SketchRNN, PCA and t-SNE》,作者:Louis Tiao,译者:海棠,审阅:阿福 

附件为原文的pdf

文章为简译,更为详细的内容,请查看原文

时间: 2024-08-25 06:10:59

通过SketchRNN、PCA和t-SNE从Google QuickDraw数据集中显示矢量图的潜在空间|附源码的相关文章

Google首页现代舞先驱玛莎&amp;#183;葛兰姆JS代码分析(附源码下载)

  2011年5月11日,GOOGLE为了纪念现代舞先驱玛莎·葛兰姆 117 周年诞辰,用巧妙的技术和奇特的创意在首页创建了一副跳舞的图,我把整个源码下载下来并加以分析和重构,效果图如下: 整个动画实际上是由155张小图片做出来的(GOOGLE的设计师太NB了),就像放电影那样,如下图: 虽然原理很简单,就是用JS来控制播放上面的图片,不过里面还有很多技巧是值得学习的,下面是我对代码的分析. HTML部分很简单,就一个div容器: <div id="hplogo">    

avalon js实现仿google plus图片多张拖动排序附源码下载_javascript技巧

源码下载:http://xiazai.jb51.net/201509/yuanma/drag_sort1(jb51.net).rar 效果展示如下: google plus     拖动+响应式效果:   要求 1. 两边对齐布局,即图片间间距一致,但左右两边的图片与边界的间距不一定等于图片间间距,兼容ie7,8,firefox,chrome. 2. 浏览器尺寸变化,在大于一定尺寸时,每行自动增加或减少图片,自动调整图片间间距,以满足两边对齐布局,这时每张图片尺寸固定(这里是200*200px)

Android源码研究的准备工作 -- 下载android源码到Ubuntu上(亲自调试,不能过分迷信GOOGLE文档)

参考资料: http://source.android.com/source/downloading.html#initializing-a-repo-client http://blog.csdn.net/xjanker2/article/details/4497013 http://www.cnblogs.com/nikyxxx/archive/2011/11/11/2246076.html http://www.cnblogs.com/yayagepei/articles/2753253.

在自己的网页页面上实现Google PR值的显示

google|pr值|网页|显示|页面 Google本身提供了查询指定的url的PageRank值的接口,知道了这个接口,就可以很容易编写脚本在页面上实现这一功能,而无需再依赖google toolbar才能进行查询.本文提供了一个用PHP实现的pr查询接口. 使用很简单,只要在需要的地方 〈?php include_once("./pr.inc.php"); echo getPR($urlToQuery); ?〉 即可显示出指定url的PageRank的数值.知道了这个数值再在其基础

Google Protocol Buffers快速入门(带生成C#源码的方法)

Google Protocol Buffers是google出品的一个协议生成工具,特点就是跨平台,效率高,速度快,对我们自己的程序定义和使用私有协议很有帮助. Protocol Buffers入门: 1.去 http://code.google.com/p/protobuf/downloads/list 下载一个源代码包和一个已编译好的二进制包 2.找一个Proto示例代码,使用命令 protoc -I=$SRC_DIR --java_out=$DST_DIR $SRC_DIR/address

请问在谷歌地图中google图标标签怎么显示?

问题描述 请问在谷歌地图中google图标标签怎么显示? google map默认的标示Marker,只能使用图片不能使用文字,label属性也只能显示首字符,怎么将一行文字显示在图标下边呢?请指教 解决方案 看一下官方文档上面应该有详细的介绍

源码-最新版Google v8如何编译成dll

问题描述 最新版Google v8如何编译成dll 40C 本人于2015年9月7日成功编译Google v8源码,得到12个lib文件,编译出来的结果跟以往不同了,以前编译出来的有一个v8_base.lib文件,现在变成了:v8_base_0.libv8_base_1.libv8_base_2.libv8_base_3.lib四个文件了.编译出来的lib文件总共有2G多,携带起来使用不方便,再说用一两个lib文件还说的过去,但是这么多,不切实际.网上很多相关资料都不能成功编译dll,改工程配置

网络爬虫-Jsoup 如何抓取GOOGLE网页数据

问题描述 Jsoup 如何抓取GOOGLE网页数据 网络爬虫新手,以前学过JAVA,所以想用JAVA来做一些数据抓取工作 在网上找的 Jsoup的JAR,试了一下感觉比较容易上手,所以想抓取GOOGLE数据 代码也是网上找的, 但是出现 timeOut,我觉得可能是GOOGLE被屏蔽的问题,我使用Ishadowsock翻墙平时,但是打开以后运货还是timeOut. 不知道各位大神能不能支支招,另外想问一下GOOGLE数据抓取有没有更好一些的开源工具,谢谢万分! Set result = new

goole 地图-google 离线地图可以做热图吗?如何实现?

问题描述 google 离线地图可以做热图吗?如何实现? 最近在做地图相关的程序,想要实现一个热图效果,我看了在线地图的话可以实现,要用到google.maps.visualization 库中提供的地图项.默认情况下,系统在加载 Maps JavaScript API 时不会加载该库,您必须使用 libraries 引导程序参数进行明确指定. google 离线地图可以做热图吗?如何实现?