【深度學習系列】用PaddlePaddle和Tensorflow實現經典CNN網絡AlexNet

  上周我們用PaddlePaddle和Tensorflow實現了圖像分類,分別用自己手寫的一個簡單的CNN網絡simple_cnn和LeNet-5的CNN網絡識別cifar-10數據集。在上周的實驗表現中,經過200次迭代后的LeNet-5的準確率為60%左右,這個結果差強人意,畢竟是二十年前寫的網絡結構,結果簡單,層數也很少,這一節中我們講講在2012年的Image比賽中大放異彩的AlexNet,并用AlexNet對cifar-10數據進行分類,對比上周的LeNet-5的效果。


什么是AlexNet?

?  AlexNet在ILSVRC-2012的比賽中獲得top5錯誤率15.3%的突破(第二名為26.2%),其原理來源于2012年Alex的論文《ImageNet Classification with Deep Convolutional Neural Networks》,這篇論文是深度學習火爆發展的一個里程碑和分水嶺,加上硬件技術的發展,深度學習還會繼續火下去。

?


AlexNet網絡結構

  由于受限于當時的硬件設備,AlexNet在GPU粒度都做了設計,當時的GTX 580只有3G顯存,為了能讓模型在大量數據上跑起來,作者使用了兩個GPU并行,并對網絡結構做了切分,如下:

?

  網絡結構

  Input輸入層

輸入為224×224×3的三通道RGB圖像,為方便后續計算,實際操作中通過padding做預處理,把圖像變成227×227×3。

  C1卷積層

該層由:卷積操作 + Max Pooling + LRN(后面詳細介紹它)組成。?

  • 卷積層:由96個feature map組成,每個feature map由11×11卷積核在stride=4下生成,輸出feature map為55×55×48×2,其中55=(227-11)/4+1,48為分在每個GPU上的feature map數,2為GPU個數;?
  • 激活函數:采用ReLU;?
  • Max Pooling:采用stride=2且核大小為3×3(文中實驗表明采用2×2的非重疊模式的Max Pooling相對更容易過擬合,在top 1和top 5下的錯誤率分別高0.4%和0.3%),輸出feature map為27×27×48×2,其中27=(55-3)/2+1,48為分在每個GPU上的feature map數,2為GPU個數;?
  • LRN:鄰居數設置為5做歸一化。?

最終輸出數據為歸一化后的:27×27×48×2。?

  ?C2卷積層

該層由:卷積操作 + Max Pooling + LRN組成?

  • 卷積層:由256個feature map組成,每個feature map由5×5卷積核在stride=1下生成,為使輸入和卷積輸出大小一致,需要做參數為2的padding,輸出feature map為27×27×128×2,其中27=(27-5+2×2)/1+1,128為分在每個GPU上的feature map數,2為GPU個數;?
  • 激活函數:采用ReLU;?
  • Max Pooling:采用stride=2且核大小為3×3,輸出feature map為13×13×128×2,其中13=(27-3)/2+1,128為分在每個GPU上的feature map數,2為GPU個數;?
  • LRN:鄰居數設置為5做歸一化。?

最終輸出數據為歸一化后的:13×13×128×2。

  C3卷積層

該層由:卷積操作 + LRN組成(注意,沒有Pooling層)?

  • 輸入為13×13×256,因為這一層兩個GPU會做通信(途中虛線交叉部分)?
  • 卷積層:之后由384個feature map組成,每個feature map由3×3卷積核在stride=1下生成,為使輸入和卷積輸出大小一致,需要做參數為1的padding,輸出feature map為13×13×192×2,其中13=(13-3+2×1)/1+1,192為分在每個GPU上的feature map數,2為GPU個數;?
  • 激活函數:采用ReLU;?

最終輸出數據為歸一化后的:13×13×192×2。

  C4卷積層

該層由:卷積操作 + LRN組成(注意,沒有Pooling層)?

  • 卷積層:由384個feature map組成,每個feature map由3×3卷積核在stride=1下生成,為使輸入和卷積輸出大小一致,需要做參數為1的padding,輸出feature map為13×13×192×2,其中13=(13-3+2×1)/1+1,192為分在每個GPU上的feature map數,2為GPU個數;?
  • 激活函數:采用ReLU;?

最終輸出數據為歸一化后的:13×13×192×2。

  C5卷積層

該層由:卷積操作 + Max Pooling組成?

  • 卷積層:由256個feature map組成,每個feature map由3×3卷積核在stride=1下生成,為使輸入和卷積輸出大小一致,需要做參數為1的padding,輸出feature map為13×13×128×2,其中13=(13-3+2×1)/1+1,128為分在每個GPU上的feature map數,2為GPU個數;?
  • 激活函數:采用ReLU;?
  • Max Pooling:采用stride=2且核大小為3×3,輸出feature map為6×6×128×2,其中6=(13-3)/2+1,128為分在每個GPU上的feature map數,2為GPU個數.?

最終輸出數據為歸一化后的:6×6×128×2。

  F6全連接層

該層為全連接層 + Dropout?

  • 使用4096個節點;?
  • 激活函數:采用ReLU;?
  • 采用參數為0.5的Dropout操作?

最終輸出數據為4096個神經元節點。

  F7全連接層

該層為全連接層 + Dropout?

  • 使用4096個節點;?
  • 激活函數:采用ReLU;?
  • 采用參數為0.5的Dropout操作?

最終輸出為4096個神經元節點。

  輸出層

該層為全連接層 + Softmax?

  • 使用1000個輸出的Softmax?

最終輸出為1000個分類。

?


?AlexNet的優勢

  1.使用了ReLu激活函數

  ----原始Relu-----

  AlexNet引入了ReLU激活函數,這個函數是神經科學家Dayan、Abott在《Theoretical Neuroscience》一書中提出的更精確的激活模型。原始的Relu激活函數(可參見 Hinton論文:《Rectified Linear Units Improve Restricted Boltzmann Machines》)我們比較熟悉,即$max(0,x)$,這個激活函數把負激活全部清零(模擬上面提到的稀疏性),這種做法在實踐中即保留了神經網絡的非線性能力,又加快了訓練速度。?
但是這個函數也有缺點:

  • 在原點不可微?
    反向傳播的梯度計算中會帶來麻煩,所以Charles Dugas等人又提出Softplus來模擬上述ReLu函數(可視作其平滑版):?

$$f(x)=log(1+e^x)$$

? ? ? ?? 實際上它的導數就是一個

\begin{equation}
f'(x)=\frac{1}{1+e^{-x}}
\end{equation}

  • 過稀疏性?

  ??當學習率設置不合理時,即使是一個很大的梯度,在經過ReLu單元并更新參數后該神經元可能永不被激活。

?   ----Leaky ReLu----?

  為了解決上述過稀疏性導致的大量神經元不被激活的問題,Leaky ReLu被提了出來: ?

?

\begin{equation}
f(x)=\left\{
\begin{aligned}
ax(x<0) \\
x(x>=0)
\end{aligned}
\right.
\end{equation}

?

  ?其中$\alpha$是人工制定的較小值(如:0.1),它一定程度保留了負激活信息。

  還有很多其他的對于ReLu函數的改進,如Parametric ReLu,Randomized ReLu等,此處就不再展開講了。

?

  2.Local Response Normalization 局部響應均值

  LRN利用相鄰feature map做特征顯著化,文中實驗表明可以降低錯誤率,公式如下:

$$b^i_{x,y}=\frac{a^i_{x,y}}{(k+\alpha \cdot \sum^{min(N-1,i+n/2)}_{j=max(0,i-n/2)}(a^i_{x,y})^2)^\beta}$$

  公式的直觀解釋如下:

?

  由于?$\alpha$都是經過了RELU的輸出,所以一定是大于0的,函數$\frac{1}{(k+\alpha \sum x^2)^\beta}$,取文中參數的圖像如下(橫坐標為$\sum x^2$):

?

?

?

  • $\sum x^2$值較小時,即當前節點和其鄰居節點輸出值差距不明顯且大家的輸出值都不太大,可以認為此時特征間競爭激烈,該函數可以使原本差距不大的輸出產生顯著性差異且此時函數輸出不飽和
  • $\sum x^2$ 值較大時,說明特征本身有顯著性差別但輸出值太大容易過擬合,該函數可以令最終輸出接近0從而緩解過擬合提高了模型泛化性。

  3.Dropout

  Dropout是文章亮點之一,屬于提高模型泛化性的方法,操作比較簡單,以一定概率隨機讓某些神經元輸出設置為0,既不參與前向傳播也不參與反向傳播,也可以從正則化角度去看待它。(關于深度學習的正則化年初的時候在公司做過一個分享,下次直接把pdf放出來)

  從模型集成的角度來看:

  

  無Dropout網絡: 

$$Y^n=W^nX^{n-1}$$
$$X^n=F(Y^n)$$

  有Dropout網絡:

$$Y^n=W^nX^{n-1}$$
$$d^{n-1}\sim Bernoulli(p)$$
$$X^n = d^{n-1} \odot F(Y^n)$$

   其中$p$為Dropout的概率(如p=0.5,即讓50%的神經元隨機失活),$n$為所在的層。

  它是極端情況下的Bagging,由于在每步訓練中,神經元會以某種概率隨機被置為無效,相當于是參數共享的新網絡結構,每個模型為了使損失降低會盡可能學最“本質”的特征,“本質”可以理解為由更加獨立的、和其他神經元相關性弱的、泛化能力強的神經元提取出來的特征;而如果采用類似SGD的方式訓練,每步迭代都會選取不同的數據集,這樣整個網絡相當于是用不同數據集學習的多個模型的集成組合。

?


用PaddlePaddle實現AlexNet

  1.網絡結構(alexnet.py)

  這次我寫了兩個alextnet,一個加上了局部均值歸一化LRN,一個沒有加LRN,對比效果如何

 1 #coding:utf-8
 2 '''
 3 Created by huxiaoman 2017.12.5
 4 alexnet.py:alexnet網絡結構
 5 '''
 6 
 7 import paddle.v2 as paddle
 8 import os
 9 
10 with_gpu = os.getenv('WITH_GPU', '0') != '1'
11 
12 def alexnet_lrn(img):
13     conv1 = paddle.layer.img_conv(
14         input=img,
15         filter_size=11,
16         num_channels=3,
17         num_filters=96,
18         stride=4,
19         padding=1)
20     cmrnorm1 = paddle.layer.img_cmrnorm(
21         input=conv1, size=5, scale=0.0001, power=0.75)
22     pool1 = paddle.layer.img_pool(input=cmrnorm1, pool_size=3, stride=2)
23 
24     conv2 = paddle.layer.img_conv(
25         input=pool1,
26         filter_size=5,
27         num_filters=256,
28         stride=1,
29         padding=2,
30         groups=1)
31     cmrnorm2 = paddle.layer.img_cmrnorm(
32         input=conv2, size=5, scale=0.0001, power=0.75)
33     pool2 = paddle.layer.img_pool(input=cmrnorm2, pool_size=3, stride=2)
34 
35     pool3 = paddle.networks.img_conv_group(
36         input=pool2,
37         pool_size=3,
38         pool_stride=2,
39         conv_num_filter=[384, 384, 256],
40         conv_filter_size=3,
41         pool_type=paddle.pooling.Max())
42 
43     fc1 = paddle.layer.fc(
44         input=pool3,
45         size=4096,
46         act=paddle.activation.Relu(),
47         layer_attr=paddle.attr.Extra(drop_rate=0.5))
48     fc2 = paddle.layer.fc(
49         input=fc1,
50         size=4096,
51         act=paddle.activation.Relu(),
52         layer_attr=paddle.attr.Extra(drop_rate=0.5))
53     return fc2
54 
55 def alexnet(img):
56     conv1 = paddle.layer.img_conv(
57         input=img,
58         filter_size=11,
59         num_channels=3,
60         num_filters=96,
61         stride=4,
62         padding=1)
63     cmrnorm1 = paddle.layer.img_cmrnorm(
64         input=conv1, size=5, scale=0.0001, power=0.75)
65     pool1 = paddle.layer.img_pool(input=cmrnorm1, pool_size=3, stride=2)
66 
67     conv2 = paddle.layer.img_conv(
68         input=pool1,
69         filter_size=5,
70         num_filters=256,
71         stride=1,
72         padding=2,
73         groups=1)
74     cmrnorm2 = paddle.layer.img_cmrnorm(
75         input=conv2, size=5, scale=0.0001, power=0.75)
76     pool2 = paddle.layer.img_pool(input=cmrnorm2, pool_size=3, stride=2)
77 
78     pool3 = paddle.networks.img_conv_group(
79         input=pool2,
80         pool_size=3,
81         pool_stride=2,
82         conv_num_filter=[384, 384, 256],
83         conv_filter_size=3,
84         pool_type=paddle.pooling.Max())
85 
86     fc1 = paddle.layer.fc(
87         input=pool3,
88         size=4096,
89         act=paddle.activation.Relu(),
90         layer_attr=paddle.attr.Extra(drop_rate=0.5))
91     fc2 = paddle.layer.fc(
92         input=fc1,
93         size=4096,
94         act=paddle.activation.Relu(),
95         layer_attr=paddle.attr.Extra(drop_rate=0.5))
96     return fc3

?

  2.訓練代碼(train_alexnet.py)

  1 #coding:utf-8
  2 '''
  3 Created by huxiaoman 2017.12.5
  4 train_alexnet.py:訓練alexnet對cifar10數據集進行分類
  5 '''
  6 
  7 import sys, os
  8 import paddle.v2 as paddle
  9 
 10 #alex模型為不帶LRN的
 11 from alexnet import alexnet
 12 #alexnet_lrn為帶有lrn的
 13 #from alextnet import alexnet_lrn
 14 with_gpu = os.getenv('WITH_GPU', '0') != '1'
 15 
 16 
 17 def main():
 18     datadim = 3 * 32 * 32
 19     classdim = 10
 20 
 21     # PaddlePaddle init
 22     paddle.init(use_gpu=with_gpu, trainer_count=7)
 23 
 24     image = paddle.layer.data(
 25         name="image", type=paddle.data_type.dense_vector(datadim))
 26 
 27     # Add neural network config
 28     # option 1. resnet
 29     # net = resnet_cifar10(image, depth=32)
 30     # option 2. vgg
 31     #net = alexnet_lrn(image)
 32     net = alexnet(image)
 33     out = paddle.layer.fc(
 34         input=net, size=classdim, act=paddle.activation.Softmax())
 35 
 36     lbl = paddle.layer.data(
 37         name="label", type=paddle.data_type.integer_value(classdim))
 38     cost = paddle.layer.classification_cost(input=out, label=lbl)
 39 
 40     # Create parameters
 41     parameters = paddle.parameters.create(cost)
 42 
 43     # Create optimizer
 44     momentum_optimizer = paddle.optimizer.Momentum(
 45         momentum=0.9,
 46         regularization=paddle.optimizer.L2Regularization(rate=0.0002 * 128),
 47         learning_rate=0.1 / 128.0,
 48         learning_rate_decay_a=0.1,
 49         learning_rate_decay_b=50000 * 100,
 50         learning_rate_schedule='discexp')
 51 
 52     # End batch and end pass event handler
 53     def event_handler(event):
 54         if isinstance(event, paddle.event.EndIteration):
 55             if event.batch_id % 100 == 0:
 56                 print "\nPass %d, Batch %d, Cost %f, %s" % (
 57                     event.pass_id, event.batch_id, event.cost, event.metrics)
 58             else:
 59                 sys.stdout.write('.')
 60                 sys.stdout.flush()
 61         if isinstance(event, paddle.event.EndPass):
 62             # save parameters
 63             with open('params_pass_%d.tar' % event.pass_id, 'w') as f:
 64                 parameters.to_tar(f)
 65 
 66             result = trainer.test(
 67                 reader=paddle.batch(
 68                     paddle.dataset.cifar.test10(), batch_size=128),
 69                 feeding={'image': 0,
 70                          'label': 1})
 71             print "\nTest with Pass %d, %s" % (event.pass_id, result.metrics)
 72 
 73     # Create trainer
 74     trainer = paddle.trainer.SGD(
 75         cost=cost, parameters=parameters, update_equation=momentum_optimizer)
 76 
 77     # Save the inference topology to protobuf.
 78     inference_topology = paddle.topology.Topology(layers=out)
 79     with open("inference_topology.pkl", 'wb') as f:
 80         inference_topology.serialize_for_inference(f)
 81 
 82     trainer.train(
 83         reader=paddle.batch(
 84             paddle.reader.shuffle(
 85                 paddle.dataset.cifar.train10(), buf_size=50000),
 86             batch_size=128),
 87         num_passes=200,
 88         event_handler=event_handler,
 89         feeding={'image': 0,
 90                  'label': 1})
 91 
 92     # inference
 93     from PIL import Image
 94     import numpy as np
 95     import os
 96 
 97     def load_image(file):
 98         im = Image.open(file)
 99         im = im.resize((32, 32), Image.ANTIALIAS)
100         im = np.array(im).astype(np.float32)
101         im = im.transpose((2, 0, 1))  # CHW
102         im = im[(2, 1, 0), :, :]  # BGR
103         im = im.flatten()
104         im = im / 255.0
105         return im
106 
107     test_data = []
108     cur_dir = os.path.dirname(os.path.realpath(__file__))
109     test_data.append((load_image(cur_dir + '/image/dog.png'), ))
110 
111     probs = paddle.infer(
112         output_layer=out, parameters=parameters, input=test_data)
113     lab = np.argsort(-probs)  # probs and lab are the results of one batch data
114     print "Label of image/dog.png is: %d" % lab[0][0]
115 
116 
117 if __name__ == '__main__':
118     main()

?

?


用Tensorflow實現AlexNet

  1.網絡結構

  1 def inference(images):
  2   '''
  3   Alexnet模型
  4   輸入:images的tensor
  5   返回:Alexnet的最后一層卷積層
  6   '''
  7   parameters = []
  8   # conv1
  9   with tf.name_scope('conv1') as scope:
 10     kernel = tf.Variable(tf.truncated_normal([11, 11, 3, 64], dtype=tf.float32,
 11                                              stddev=1e-1), name='weights')
 12     conv = tf.nn.conv2d(images, kernel, [1, 4, 4, 1], padding='SAME')
 13     biases = tf.Variable(tf.constant(0.0, shape=[64], dtype=tf.float32),
 14                          trainable=True, name='biases')
 15     bias = tf.nn.bias_add(conv, biases)
 16     conv1 = tf.nn.relu(bias, name=scope)
 17     print_activations(conv1)
 18     parameters += [kernel, biases]
 19 
 20   # lrn1
 21   with tf.name_scope('lrn1') as scope:
 22     lrn1 = tf.nn.local_response_normalization(conv1,
 23                                               alpha=1e-4,
 24                                               beta=0.75,
 25                                               depth_radius=2,
 26                                               bias=2.0)
 27 
 28   # pool1
 29   pool1 = tf.nn.max_pool(lrn1,
 30                          ksize=[1, 3, 3, 1],
 31                          strides=[1, 2, 2, 1],
 32                          padding='VALID',
 33                          name='pool1')
 34   print_activations(pool1)
 35 
 36   # conv2
 37   with tf.name_scope('conv2') as scope:
 38     kernel = tf.Variable(tf.truncated_normal([5, 5, 64, 192], dtype=tf.float32,
 39                                              stddev=1e-1), name='weights')
 40     conv = tf.nn.conv2d(pool1, kernel, [1, 1, 1, 1], padding='SAME')
 41     biases = tf.Variable(tf.constant(0.0, shape=[192], dtype=tf.float32),
 42                          trainable=True, name='biases')
 43     bias = tf.nn.bias_add(conv, biases)
 44     conv2 = tf.nn.relu(bias, name=scope)
 45     parameters += [kernel, biases]
 46   print_activations(conv2)
 47 
 48   # lrn2
 49   with tf.name_scope('lrn2') as scope:
 50     lrn2 = tf.nn.local_response_normalization(conv2,
 51                                               alpha=1e-4,
 52                                               beta=0.75,
 53                                               depth_radius=2,
 54                                               bias=2.0)
 55 
 56   # pool2
 57   pool2 = tf.nn.max_pool(lrn2,
 58                          ksize=[1, 3, 3, 1],
 59                          strides=[1, 2, 2, 1],
 60                          padding='VALID',
 61                          name='pool2')
 62   print_activations(pool2)
 63 
 64   # conv3
 65   with tf.name_scope('conv3') as scope:
 66     kernel = tf.Variable(tf.truncated_normal([3, 3, 192, 384],
 67                                              dtype=tf.float32,
 68                                              stddev=1e-1), name='weights')
 69     conv = tf.nn.conv2d(pool2, kernel, [1, 1, 1, 1], padding='SAME')
 70     biases = tf.Variable(tf.constant(0.0, shape=[384], dtype=tf.float32),
 71                          trainable=True, name='biases')
 72     bias = tf.nn.bias_add(conv, biases)
 73     conv3 = tf.nn.relu(bias, name=scope)
 74     parameters += [kernel, biases]
 75     print_activations(conv3)
 76 
 77   # conv4
 78   with tf.name_scope('conv4') as scope:
 79     kernel = tf.Variable(tf.truncated_normal([3, 3, 384, 256],
 80                                              dtype=tf.float32,
 81                                              stddev=1e-1), name='weights')
 82     conv = tf.nn.conv2d(conv3, kernel, [1, 1, 1, 1], padding='SAME')
 83     biases = tf.Variable(tf.constant(0.0, shape=[256], dtype=tf.float32),
 84                          trainable=True, name='biases')
 85     bias = tf.nn.bias_add(conv, biases)
 86     conv4 = tf.nn.relu(bias, name=scope)
 87     parameters += [kernel, biases]
 88     print_activations(conv4)
 89 
 90   # conv5
 91   with tf.name_scope('conv5') as scope:
 92     kernel = tf.Variable(tf.truncated_normal([3, 3, 256, 256],
 93                                              dtype=tf.float32,
 94                                              stddev=1e-1), name='weights')
 95     conv = tf.nn.conv2d(conv4, kernel, [1, 1, 1, 1], padding='SAME')
 96     biases = tf.Variable(tf.constant(0.0, shape=[256], dtype=tf.float32),
 97                          trainable=True, name='biases')
 98     bias = tf.nn.bias_add(conv, biases)
 99     conv5 = tf.nn.relu(bias, name=scope)
100     parameters += [kernel, biases]
101     print_activations(conv5)
102 
103   # pool5
104   pool5 = tf.nn.max_pool(conv5,
105                          ksize=[1, 3, 3, 1],
106                          strides=[1, 2, 2, 1],
107                          padding='VALID',
108                          name='pool5')
109   print_activations(pool5)
110 
111   return pool5, parameters

?

  完整代碼可見:alexnet_tf.py?

?


實驗結果對比

  三個代碼跑完后,對比了一下實驗結果,如圖所示:

?

  可以看到,在batch_size,num_epochs,devices和thread數都相同的條件下,加了LRN的paddlepaddle版的alexnet網絡結果效果最好,而時間最短的是不加LRN的alexnet,在時間和精度上都比較平均的是tensorflow版的alexnet,當然,tf版的同樣加了LRN,所以LRN對于實驗效果還是有一定提升的。

?


總結

  AlexNet在圖像分類中是一個比較重要的網絡,在學習的過程中不僅要學會寫網絡結構,知道每一層的結構,更重要的是得知道為什么要這樣設計,這樣設計有什么好處,如果對某些參數進行一些調整結果會有什么變化?為什么會產生這樣的變化。在實際應用中,如果需要對網絡結構做一些調整,應該如何調整使得網絡更適合我們的實際數據?這些才是我們關心的。也是面試中常常會考察的點。昨天面試了一位工作五年的算法工程師,問道他在項目中用的模型是alexnet,對于alexnet的網絡結構并不是非常清楚,如果要改網絡結構也不知道如何改,這樣其實不好,僅僅把模型跑通只是第一步,后續還有很多工作要做,這也是作為算法工程師的價值體現之一。本文對于alexnet的網絡結構參考我之前的領導寫的文章,如過有什么不懂的可以留言。

?

?ps:為了方便大家及時看到我的更新,我搞了一個公眾號,以后文章會同步發布與公眾號和博客園,這樣大家就能及時收到通知啦,有不懂的問題也可以在公眾號留言,這樣我能夠及時看到并回復。(公眾號剛開始做,做的比較粗糙,里面還沒有東西 = =,后期會慢慢完善~~)

可以通過掃下面的二維碼或者直接搜公眾號:CharlotteDataMining 就可以了,謝謝關注^_^

?

參考文獻

1.AlexNet:?http://www.cs.toronto.edu/~fritz/absps/imagenet.pdf

?

我的博客即將同步至騰訊云+社區,邀請大家一同入駐。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/392038.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/392038.shtml
英文地址,請注明出處:http://en.pswp.cn/news/392038.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

圖片獲取像素坐標html,HTML5畫布Canvas圖片抽取、像素信息獲取、命中檢測

今天主要介紹canvas中比較強大的功能比如將畫布內容抽取為圖片獲取、修改畫布的像素信息以及畫布的命中檢測首先我仍然需要創建畫布圖片抽取首先要明確的一點是toDataURL()是canvas對象自身的方法而不是環境對象的這個方法會將canvas的內容抽取為一張圖片(base64編碼)我們來看一…

CentOS6 下Samba服務器的安裝與配置

原地址&#xff1a;http://www.cnblogs.com/mchina/archive/2012/12/18/2816717.html 一、簡介 Samba是一個能讓Linux系統應用Microsoft網絡通訊協議的軟件&#xff0c;而SMB是Server Message Block的縮寫&#xff0c;即為服務器消息塊 &#xff0c;SMB主要是作為Microsoft的網…

傅里葉變換 直觀_A / B測試的直觀模擬

傅里葉變換 直觀Many of us have heard, read, or even performed an A/B Test before, which means we have conducted a statistical test at some point. Most of the time, we have worked with data from first or third-party sources and performed these tests with ea…

tableau for循環_Tableau for Data Science and Data Visualization-速成課程

tableau for循環Tableau is software that can help you see and understand your data. It is used for data science and data visualization. Tableau allows you to connect to almost any database, drag and drop to create visualizations, and share with a click.Tabl…

請求接口時使用時間戳

&tnew Date().getTime()轉載于:https://www.cnblogs.com/Glant/p/11271960.html

Java—servlet簡單使用

【步驟 1】創建一個名為 input.html 的 HTML 頁面&#xff0c;其中包括一個表單&#xff0c;表單中包含兩 個文本域&#xff0c;分別供用戶輸入學號和姓名&#xff0c;該頁面也包含提交和重置按鈕。 【步驟 2】定義一個名為 com.demo.Student 類&#xff0c;其中包括學號 sno 和…

phpstrom+phpstudy+postman

1.打開phpstudy xdebug 擴展 2.修改php.ini [XDebug]xdebug.profiler_output_dir"D:\phpStudy\tmp\xdebug"xdebug.trace_output_dir"D:\phpStudy\tmp\xdebug"zend_extension"D:\phpStudy\php\php-5.5.38\ext\php_xdebug.dll";是否允許Xdebug跟蹤…

SIP協議

SIP協議 SIP協議主要包括 SIP頭 SIP內容 和附加內容三個部分 項目格式備注示例SIP頭一行&#xff0c;以\r\n結尾REGISTER sip:172.30.2.35 SIP/2.0\r\nSIP內容很多行&#xff0c;每行為Key&#xff0c;Value的形式CSeq: 1 REGISTER\r\n附加內容很多行1 SIP頭 項目格式含義示例I…

android emmc 命令,使用CoreELEC的ceemmc工具將系統寫入emmc

最近在折騰電視盒子&#xff0c;CoreELEC是專門為晶晨CPU開發系統&#xff0c;個人覺的非常不錯&#xff0c;相關資料可以百度。這里介紹將卡載系統刷入emmc內置存儲的方法。因為找不到相關的教程&#xff0c;只在官網上找到了ceemmc這個工具的使用說明&#xff0c;所以搬過來。…

ios 自定義字體_如何僅用幾行代碼在iOS應用中創建一致的自定義字體

ios 自定義字體by Yuichi Fujiki藤木雄一 In this article, youll learn how to create a unified custom look throughout your app with these simple tricks.在本文中&#xff0c;您將學習如何使用這些簡單的技巧在整個應用程序中創建統一的自定義外觀。 我們想做什么 (Wh…

truncate 、delete與drop區別

相同點&#xff1a; 1.truncate和不帶where子句的delete、以及drop都會刪除表內的數據。 2.drop、truncate都是DDL語句(數據定義語言),執行后會自動提交。 不同點&#xff1a; 1. truncate 和 delete 只刪除數據不刪除表的結構(定義)drop 語句將刪除表的結構被依賴的約束(const…

Java—jsp編程

1. 編寫 login.jsp&#xff0c;登錄時只輸入一個昵稱。但要檢查昵稱是否已經被其他用戶使用。 源代碼 Login.jsp <% page contentType"text/html;charsetUTF-8" language"java" %><%request.setCharacterEncoding("UTF-8"); //設置編…

Java 8 Optional類深度解析

2019獨角獸企業重金招聘Python工程師標準>>> 身為一名Java程序員&#xff0c;大家可能都有這樣的經歷&#xff1a;調用一個方法得到了返回值卻不能直接將返回值作為參數去調用別的方法。我們首先要判斷這個返回值是否為null&#xff0c;只有在非空的前提下才能將其作…

鴿子 迷信_人工智能如何幫助我戰勝鴿子

鴿子 迷信鴿子回避系統 (Pigeon Avoidance System) Disclaimer: You are reading Part 1 that gives an overview of the project. Part 2 describes the technical setup and data collection. Part 3 is about how to train the Pigeon Recognition Model and run it on Rasp…

華為鴻蒙會議安排,2020華為HDC日程確定,鴻蒙、HMS以及EMUI 11成最關注點

原標題&#xff1a;2020華為HDC日程確定&#xff0c;鴻蒙、HMS以及EMUI 11成最關注點HDC&#xff1a;華為開發者大會&#xff0c;目前已經確定將在9月10日正式開幕。日前華為已經在其官網公布了HDC的日程&#xff0c;從現在的消息看華為開發者大會有三大點最受業內關注。鴻蒙操…

反射、元類

一、反射 1、什么是反射&#xff1a;就是反省&#xff0c;自省的意思 反射指的是一個對象應該具備&#xff0c;可以增、刪、改、查屬性的能力&#xff0c;通過字符串來操作屬性 涉及的四個函數&#xff0c;這四個函數就是普通的內置函數&#xff0c;只是沒有下劃線而已&#xf…

Java—簡單的圖書管理系統

簡單的圖書管理系統 通過數據源和DAO對象訪問數據庫。其中JavaBeans實現模型&#xff0c;訪問數據庫&#xff0c;Servlet實現控制器&#xff0c;JSP頁面實現視圖。 ? 模型包括2個JavaBean&#xff1a;BookBean用于存放圖書信息&#xff0c;BookDAO用于訪問數據庫。 ? 控制器包…

成功的秘訣是什么_學習編碼的10個成功秘訣

成功的秘訣是什么This post was originally published on Coder-Coder.com.該帖子最初發布在Coder-Coder.com上 。 If you’re teaching yourself how to code, you may have more questions than answers when you’re starting out.如果您正在教自己如何編碼&#xff0c;那么…

ZJUT 地下迷宮 (高斯求期望)

http://cpp.zjut.edu.cn/ShowProblem.aspx?ShowID1423 設dp[i]表示在i點時到達終點要走的期望步數&#xff0c;那么dp[i] ∑1/m*dp[j] 1&#xff0c;j是與i相連的點&#xff0c;m是與i相鄰的點數。建立方程組求解。重要的一點是先推斷DK到達不了的點。須要bfs預處理一下進行…

html收款頁面模板,訂單收款.html

&#xfeff;訂單收款$axure.utils.getTransparentGifPath function() { return resources/images/transparent.gif; };$axure.utils.getOtherPath function() { return resources/Other.html; };$axure.utils.getReloadPath function() { return resources/reload.html; };…