0%

吴恩达深度学习 C4W1 卷积神经网络 CNN

CNN

  • 卷积层
  • 池化层
  • 全连接层

image-20200324153929956

卷积层

设第l层(layer l)是卷积层:

则:

每个filter的通道数:$n_c = 输入图像的通道数 = n_c^{[l-1]}$

每个filter,即权重的参数个数:$f^{[l]} × f^{[l]}$

filters的数目:$n_c^{[l]} = 检测的特征数量$

输出图像的高度:$n_H^{[l]} = ⌊\frac{n_H^{[l-1]} + 2p^{[l]} - f^{[l]}}{s^{[l]}} + 1⌋$

输出图像的宽度:$n_W^{[l]} = ⌊\frac{n_W^{[l-1]} + 2p^{[l]} - f^{[l]}}{s^{[l]}} + 1⌋$

输出图像的通道数:$n_c^{[l]} = l层的filters数目$


  • kernel(核)/ filter(过滤器)

  • 检测n个边缘特征,就设置n个filters,输出图片的通道数也等于n。

  • padding卷积

    • Valid卷积:不填充
    • Same卷积:填充后输出和输入的大小一致
      • 即$\frac{n + 2p -f}{s} + 1 = n$
  • 推荐只是用奇数的过滤器,即将f设为奇数

  • 向下取整操作,意味着只有当filter完全包含在(填充完的)图像内部时,才进行相乘操作。

  • 三维卷积

    • filters的通道数必须和输入图像的通道数匹配

    • 假设filter size=3,通道数=3,则每次,先取图片红色通道的9个数字,与filter第一通道的9个数相乘再相加;然后再分别取绿色通道、蓝色通道执行相同操作,再把这些数相加,得到输出值

      image-20200324150304511

    • 每个filter得到的输出图像通道数仍为1,与输入图像通道数无关。

    • 输出图像最终的通道数 = filters 个数

  • 即使输入图片很大,CNN的参数却很少,可以避免过拟合。

  • 卷积层2个主要优势:

    • 参数共享
    • 稀疏连接

池化层

  • 池化层可以缩减模型大小,提高计算速度,同时提高所提取特征的鲁棒性

  • 两种池化类型:

    • 最大池化:最常用
    • 平均池化:用于很深的神经网络

    最常用的是最大池化

  • 池化有一组超参数(f,s等),但是没有需要学习的参数,所以一旦确定了f,s,它就是一个固定运算,梯度下降无需改变任何值。

    在计算神经网络有多少层时,通道只统计具有权重和参数的层。而池化层没有权重和参数,只有一些超参数,所以池化层和卷积层共同作为一层。

  • 池化是对输入图像$n_c$个通道中的每个通道,都单独执行池化计算。所以输出通道与输入通道数相同

    image-20200324152439217

  • 池化的超级参数包括filter size(f)和步幅(s)

    常用的超参数设置为:f = 2, s = 2其效果相当于高度和宽度减一半

    也有 f = 3, s = 2的情况

  • 最大池化很少用到超参数padding,所以最常用的:p = 0

  • :虽然吴恩达在视频中说,same卷积,就是填充后,你的输出大小和输入大小一样。而tensorflow中,卷积和池化的padding处理相同,那么最大池化如果用了same padding,理论上输出的大小也不变,但实际并不是这样的。

    我建立了一个CNN,理所当然地认为最大池化的padding设为same后,输出的长宽不变,但是报错:

    1
    tensorflow.python.framework.errors_impl.InvalidArgumentError: Input to reshape is a tensor with 819200 values, but the requested shape has 52428800 [Op:Reshape]

    报错出现在下面代码的最后一行。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    print(inputs.shape)                     # (32, 80, 160, 1)
    x = self.conv1(inputs) # [batch_size, 80, 160, 32]
    print(x.shape) # (32, 80, 160, 32)
    x = self.pool1(x) # [batch_size, 80, 160, 32]
    print(x.shape) # (32, 40, 80, 32)
    x = self.conv2(x) # [batch_size, 80, 160, 64]
    print(x.shape) # (32, 40, 80, 64)
    x = self.pool2(x) # [batch_size, 80, 160, 64]
    print(x.shape) # (32, 20, 40, 64)
    x = self.conv3(x) # [batch_size, 80, 160, 128]
    print(x.shape) # (32, 20, 40, 128)
    x = self.pool3(x) # [batch_size, 80, 160, 128]
    print(x.shape) # (32, 10, 20, 128)
    x = self.flatten(x) # [batch_size, 80 * 160 * 128]

    print输出的是实际维度,上一行的注释则是我原本认为的维度。原来,即使在最大池化中padding选了same,输出维度也不是就等于输入维度,因为SAME padding输入输出一致的前提是strides = 1,而我设置的strides = 2

    The TensorFlow Convolution example gives an overview about the difference between SAME and VALID :
    For the SAME padding, the output height and width are computed as:

    out_height = ceil(float(in_height) / float(strides[1]))
    out_width = ceil(float(in_width) / float(strides[2]))
    

    And

    For the VALID padding, the output height and width are computed as:
    out_height = ceil(float(in_height - filter_height + 1) / float(strides[1]))
    out_width = ceil(float(in_width - filter_width + 1) / float(strides[2]))
    

    可以发现,池化层设置如下时,输出的长宽仍然会减半。

    1
    2
    3
    4
    5
    self.pool3 = tf.keras.layers.MaxPool2D(
    pool_size=[2, 2],
    strides=2,
    padding='same'
    )

    因为$H{OUT} = H{IN} / strides = H_{IN} / 2$,相当于只是抵消了filter_size的影响,而不对strides起作用,所以输出的长宽依旧减半了。

    池化本身就是所建模型大小(降维的)!

    参考:https://www.zhihu.com/question/376747493

    https://www.imooc.com/article/73051

  • 若最大池化的输入:$n_H × n_W × n_c$,设 p = 0

    则,输出:$⌊\frac{n_H - f}{s} + 1⌋ × ⌊\frac{n_W - f}{s} + 1⌋ × n_c$


  • 池化层没有参数,卷积层参数相对较少,许多参数都存在于神经网络的全连接层。
  • 尽量不要自己设置超参数,而是查看文献中别人使用了哪些超参数,选一个别人任务中效果很好的架构,那么它也有可能适用于你自己的应用程序。

C2W1 深度学习的实践层面

吴恩达深度学习C2W1 深度学习的实践层面

  • 如何配置训练集、验证集、测试集
  • 如何分析偏差、方差,如何处理高偏差or高方差or高偏差和高方差共存的问题
  • 如何在神经网络中应用不同形式的正则化(正则化解决高方差过拟合问题)
    • L2正则化
    • dropout
    • 其他正则化(数据扩增、early stopping)
  • 加快神经网络训练速度的技巧(归一化输入)
  • 梯度检验(调试后向传播是否正确)

编程作业

1、初始化参数

  1. 不同的初始化方法可能导致性能最终不同

  2. 随机初始化有助于打破对称,使得不同隐藏层的单元可以学习到不同的参数。

  3. 初始化时,初始值不宜过大。

  4. He初始化搭配ReLU激活函数常常可以得到不错的效果。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    # GRADED FUNCTION: initialize_parameters_he

    def initialize_parameters_he(layers_dims):
    """
    Arguments:
    layer_dims -- python array (list) containing the size of each layer.

    Returns:
    parameters -- python dictionary containing your parameters "W1", "b1", ..., "WL", "bL":
    """

    np.random.seed(3)
    parameters = {}
    L = len(layers_dims) - 1 # integer representing the number of layers

    for l in range(1, L + 1):
    ### START CODE HERE ### (≈ 2 lines of code)
    parameters['W' + str(l)] = np.random.randn(layers_dims[l], layers_dims[l - 1]) * np.sqrt(2 / layers_dims[l - 1])
    parameters['b' + str(l)] = np.zeros((layers_dims[l], 1))
    ### END CODE HERE ###

    return parameters

2、正则化

解决过拟合(高方差)

  • L2正则化(“权重衰减”:权重被改变到较小的值)

    • compute_cost_with_regularization(A3, Y, parameters, lambd)

      计算代价函数时增加正则化项

    • backward_propagation_with_regularization(X, Y, cache, lambd)

      权重矩阵的梯度计算要加上正则化项的导数

    若 λ 过大,可能导致高偏差

  • dropout正则化

    • forward_propagation_with_dropout instead of forward_propagation.
    • backward_propagation_with_dropout instead of backward_propagation.

    正则化只用于训练,不要在测试中使用

3、梯度校验

C2W2 优化算法

吴恩达深度学习C2W2 优化算法

1、mini-batch 梯度下降法

  • 如果训练集较小(小于2000个样本),则直接使用 batch 梯度下降法(即 mini-batch size = m)
  • 如果训练样本数据较大,mini-batch size 一般设为 64-512 ,设为 2 的 n 次方,代码运行快一些。也有设为 1024 的,比较少见

使用 batch 梯度下降法,一次遍历训练集只能做一个梯度下降;使用 mini-batch 梯度下降法,一次遍历训练集(1 epoch),能做 n 个梯度下降(n 为划分的 mini-batch 数目)

2、优化算法(加速梯度下降)

2.1、指数加权平均

占用极少内存(只占用一行代码,且计算指数加权平均数也只占用当行数字的存储,只需要把最新数据代入公式,不断覆盖就可以)

偏差修正

当 β 值设的较大时(eg. 0,98),初期估测值不准(过小),可以用 $\frac{v_t}{1 - \beta^t}$ 代替 $v_t$ 来估测第 t 天的温度值。

随着 t 的增大,$\beta^t$ 的值接近于 0 ,偏差修正几乎没有作用。

但如果你关心初始时期的偏差,在刚开始计算指数加权平均时,偏差修正能帮你在早期获取更好的估测。,使得指数加权平均数的运算更加准确(特别是在估测初期)

2.2 (Momentum)动量梯度下降法

基本思想计算梯度的指数加权平均数,并利用该梯度更新你的权重。

目的:加速梯度下降

1
2
On iteration t:
# Compute dW,db on the current mini-batch

有2个超参数,α 和 β。β 的值常设为0.9,这相当于平均了前10次迭代的梯度,而10次迭代后已过了初始阶段,所以不需要偏差修正。

原理:通过以上的公式计算加权平均,结合下面的图:

  • 在纵轴(偏置b)方向,平均的过程中,正负相抵,所以接近于0,所以用指数加权平均数更新偏置b,在纵轴方向波动减小。
  • 在横轴(权重W)方向,由于所有微分都指向横轴方向,所以平均值仍较大,所以用指数加权平均数更新权重W,在横轴方向依旧有更快的学习速度

image-20200307173423707

2.3 RMSprop算法(均方根算法)

目的:加速梯度下降

RMSprop和Momentum有很相似的一点,可以消除梯度下降中的摆动,并允许你使用一个更大的学习率α,从而加快你的学习算法速度。

1
2
On iteration t:
# Compute dW,db on the current mini-batch

原理:因为db较大,dW较小(可以从2.2的图看出纵轴的倾斜程度大,所以b的梯度db大);所以$S{db}$也较大,而$S{dW}$则较小;所以相当于在更新时b的学习率较小,而W的学习率较大;这就达到了消除纵向摆动,加快横向更新速度的目的。

不过为了保证在更新参数时不会出现除以0的情况,最后一步的更新操作通常更改为:

2.4 Adam算法

基本思想结合 Momentum 和 RMSprop

1
Adam optimization algorithm

0初始化:

1
2
On iteration t:
# Compute dW,db on the current mini-batch

计算Momentum指数加权平均:

RMSprop:

偏差修正:

更新权重:

以上就是Adam算法,超参数缺省值如下:

一般直接使用这些超参数的缺省值,不需要修改。

2.5 学习率衰减

基本思想:学习率随时间慢慢减少。在学习初期学习率较大,即有较大的更新步伐;当开始收敛时,学习率较小,即更新步伐较小。

几种学习率衰减模式:

  • 指数衰减:

TensorFlow

1、GPU版TensorFlow安装

参考:https://tf.wiki/zh/basic/installation.html

  1. 安装NVIDIA 驱动程序

    访问NVDIA官网下载:https://www.nvidia.com/Download/index.aspx?lang=en-us

    可在cmd中输入nvidia-smi -L查看显卡型号,下载相应版本的驱动程序,安装后重启电脑。

  2. 建立conda虚拟环境并进入

    打开Anaconda Prompt,输入:(python版本号填写自己的python环境版本)

    1
    2
    conda create --name tf2 python=3.7      # “tf2”是你建立的conda虚拟环境的名字
    conda activate tf2 # 进入名为“tf2”的conda虚拟环境

    进入虚拟环境后命令行最左边或显示虚拟环境名称(tf2):

    image-20200305145416211

    (注:其他关于虚拟环境的操作如下:

    1
    2
    3
    4
    5
    conda create --name [env-name]      # 建立名为[env-name]的Conda虚拟环境
    conda activate [env-name] # 进入名为[env-name]的Conda虚拟环境
    conda deactivate # 退出当前的Conda虚拟环境
    conda env remove --name [env-name] # 删除名为[env-name]的Conda虚拟环境
    conda env list # 列出所有Conda虚拟环境
  3. 安装 CUDA Toolkit 和 cuDNN。

    1
    2
    3
    4
    # 注:以下两行命令中的版本号严格按照https://www.tensorflow.org/install/gpu#software_requirements 安装,
    # 对于 TensorFlow 2.1,可使用
    conda install cudatoolkit=10.1
    conda install cudnn=7.6.5
  4. 安装gpu版tensorflow

    1
    2
    3
    # pip install tensorflow-gpu # 会自动安装对应版本的 CUDA Toolkit 和 cuDNN
    pip install tensorflow
    # 从 TensorFlow 2.1 开始,pip 包 tensorflow 即同时包含 GPU 支持

    注:从 TensorFlow 2.1 开始,pip 包 tensorflow 即同时包含 GPU 支持,无需通过特定的 pip 包 tensorflow-gpu 安装 GPU 版本。如果对 pip 包的大小敏感,可使用 tensorflow-cpu 包安装仅支持 CPU 的 TensorFlow 版本。

    也可以使用 conda install tensorflow 来安装 TensorFlow,不过 conda 源的版本往往更新较慢,难以第一时间获得最新的 TensorFlow 版本.

    安装完后,可以通过命令pip list查看安装的包列表

  5. 检测是否正确安装

    (如果你在 Windows 下安装了 TensorFlow 2.1 正式版,可能会在导入 TensorFlow 时出现 DLL 载入错误 。此时安装 Microsoft Visual C++ Redistributable for Visual Studio 2015, 2017 and 2019 即可正常使用。)

    在虚拟环境中输入python,进入python环境,输入:

    1
    import tensorflow as tf

    如果报错:

    1
    2
    3
    ImportError: DLL load failed: 找不到指定的模块。

    Failed to load the native TensorFlow runtime.

    进入https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads安装Visual Studio 2015, 2017 and 2019即可。

  6. 第一个程序

    在虚拟环境中输入python,进入python环境,输入:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import tensorflow as tf

    A = tf.constant([[1, 2], [3, 4]])
    # 运行这一行若报错cudaGetDevice() failed. Status: CUDA driver version is insufficient for CUDA runtime version
    # 跳转到第1步,安装一下NVIDIA 驱动程序即可

    B = tf.constant([[5, 6], [7, 8]])
    C = tf.matmul(A, B)

    print(C)

    输出如下结果表明安装成功

    1
    2
    3
    tf.Tensor(
    [[19 22]
    [43 50]], shape=(2, 2), dtype=int32)
  7. pycharm

    新建项目,选择已存在的虚拟环境tf2

    image-20200312151710275

2、错误记录

1、module 'tensorflow' has no attribute 'keras'

错误详情:

我建立了一个目录如下:

image-20200306170836393

然后我在该目录下新建了tensorboard.py,运行时报错module 'tensorflow' has no attribute 'keras'。并且去运行以上其他py文件也出现该报错,但是在建立tensorboard.py前运行都正常。

tensorboard.py开头如下:

1
2
import tensorflow as td
from MLP import MLP, MNISTLoader

现在运行该文件夹下所有的py文件都报如标题所示错误,且都指向MLP.py文件的一行:

1
class MLP(tf.keras.Model):

去网上找解决方案,基本都是:

1、更新tensorflow

2、更新keras

但我都试过了,没有用。而且,我实在pip install tensorflow时,自动安装的keras,因此不可能出现keras和tensorflow版本不匹配的问题。

于是,我把tensorboard.py文件删了,结果其他所有py文件都能正常运行了。

我也不知道这是为什么,不知道tensorboard.py有啥问题。改代码来自https://tf.wiki/zh/basic/tools.html#id3。只是:

1
2
from zh.model.mnist.mlp import MLP
from zh.model.utils import MNISTLoader

修改为:

1
from MLP import MLP, MNISTLoader

感觉很玄学。我就放弃了这个文件,直接删掉。然后把它的训练过程可视化代码插入到checkpoint.py中,能够正常运行。

hexo博客迁移(换电脑继续更新博客)

更换电脑/重装系统后的操作:

  • 安装Git(廖雪峰的Git教程https://www.liaoxuefeng.com/wiki/896043488029600)

  • 安装完Git后,Git Bash输入如下指令设置信息

    1
    2
    $ git config --global user.name "Your Name"	# 替换成自己的名字
    $ git config --global user.email "email@example.com" # 替换成自己的邮箱地址
  • 设置 SSH 密钥。使用如下命令生成SSH密钥

    1
    $ ssh-keygen
  • 输入以上命令后,一路按enter键采用默认值

  • 输入如下命令查看并复制SSH密钥

    1
    $ cat ~/.ssh/id_rsa.pub

    复制SSH密钥,格式如下:

    1
    ssh-rsa ...
  • 到GitHub的SSH设置页面(导航栏头像 - Settings - SSH and GPG keys),点击New SSH key按钮,将复制的内容粘贴到Key输入框中,再填写标题,eg.”My New PC”,最后点击“Add SHH key”按钮保存

  • 克隆。

    在本地新建博客文件夹,比如”D:\Blog”

    在该文件夹下Git Bash Here,使用如下命令拷贝博客的GitHub仓库到本地(默认分支为source)

    1
    2
    $ git clone git@github.com:PanosPanay/PanosPanay.github.io.git
    # clone后面的一串可以通过点击GitHub博客仓库的Clone or download复制得到

    1579830393814

  • 安装Node.js

    下载地址:https://nodejs.org/zh-cn/download/

    按照提示安装即可。

    正常安装完成后,环境变量就已经被配置好了,能正常使用 npm 命令。

    输入如下命令分别出现对应的版本号即代表安装成功

    1
    2
    $ node -v
    $ npm -v
  • 如果成功执行上述步骤后,在执行下述步骤中的hexo命令,遇到报错bash: hexo: command not found,则需要配置环境变量。参考https://blog.csdn.net/qq_36759224/article/details/100411949

  • 在本地新拷贝的D:\Blog\PanosPanay.github.io文件夹下,Git Bash Here,分别输入如下命令(参考:https://www.zhihu.com/question/21193762)

    1
    2
    3
    $ npm install hexo
    $ npm install
    $ npm install hexo-deployer-git
  • 将原来电脑上博客文件夹下的如下文件复制粘贴到当前博客文件夹(主题等配置)

    1
    2
    3
    4
    5
    6
    _config.yml
    package.json
    scaffolds/
    source/
    themes/
    deploy.sh
  • 更新博客,增改博文

  • 分别执行如下命令,将改动推送到Github

    1
    2
    3
    $ git add .
    $ git commit -m "..."
    $ git push origin source # 之后可直接 git push
  • 发布到master分支

    1
    $ sh deploy.sh

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

BMP图像处理

本篇博客记录完成《数字媒体内容综合设计与实验》的图像处理实验的学习过程。要求实现一个显示bmp文件的程序(语言不限),并实现图像亮度、对比度调整,图像平移、放大、旋转和镜像。

参考:

https://blog.csdn.net/lanbing510/article/details/8176231

BMP文件格式

1. 位图文件头(bmp file header) - 14字节

字段 字节数 说明
bfType 2 文件类型
BMP文件这两个字节为0x4d42,对应字符’BM’
bfSize 4 文件大小
bfReserved1 2 保留字段,必须设为0
bfReserved2 2 保留字段,必须设为0
bfOffBits 4 从文件头到位图数据的偏移量,即:
偏移量=文件头+信息头+调色板长度

用UltraEdit打开图片001.bmp(24位真彩色bmp图):

001

bmp-file-header

注意读取字节反向

字段 说明
bfType 0x4D42 BM
bfSize 0x0017057A = 1508730字节 = 1.43MB 等同于右键图片属性中显示的大小
bfOffBits 0x00000036 = 54字节 = 文件头14 + 信息头40 + 调色板0

2. 位图信息头(bitmap information) - 40字节

字段 字节数 说明
biSize 4 信息头的大小
BMP文件为0x28,即40字节
biWidth 4 图像的宽,单位是像素
biHeight 4 图像的高,单位是像素
biPlanes 2 颜色平面数,总设为1
biBitCount 2 每像素比特数,=比特数/像素数
即每个像素用多少位表示
biCompression 4 图像的压缩类型
最常用的是0,即BI_RGB格式,表示不压缩
biSizeImage 4 位图数据的大小
图像大小=文件大小bfSize-偏移量bfOffBits
BI_RGB格式时,可设置为0
biXPelsPerMeter 4 水平分辨率,单位是像素/米,有符号整数
biYPelsPerMeter 4 垂直分辨率,单位是像素/米,有符号整数
biClrUsed 4 位图使用的调色板中的颜色索引数
0表示使用所有的调色板选项
biClrImportant 4 对图像显示有重要影响的颜色索引数目
0表示所有都重要

bitmap-information

字段 说明
biSize 0x00000028 = 40字节 BMP文件信息头大小
biWidth 0x000002A6 = 678像素 图片宽678像素
biHeight 0x000002E5 = 741像素 图片高741像素
biBitCount 0x0018 = 24位 24位真彩色图片
biCompression 0x00000000 不压缩
biSizeImage 0x00170544 = 1508676字节 =bfOffbits-54

理论上,biSizeImage = biWidth*biHeight*biBitCount/8,由于Windows行扫描的最小单位为4字节,所以此处biWidth应向上取4的倍数。

但是从上面这张图来看,biSizeImage = 1508686字节,确实等于bfOffbits-54,但是不等于680*741*24/8 =1511640字节,也不等于678*741*24/8 =1507194字节,不解???

3. 调色板(color palette) - 可选项

详见https://blog.csdn.net/lanbing510/article/details/8176231

采用24位真彩色位图,无需使用调色板模块。用3个字节(24位)的实际RGB值表示一个像素。

同理,32位真彩色位图也不需要调色板模块。用4个字节(32位)的RGBA值表示一个像素。

4. 位图数据(bitmap data)

未完待续。。。

Python-Day13-进程和线程

参考:

[Python - 100天从新手到大师]: https://github.com/jackfrued/Python-100-Days

1、笔记

2、Python中的多进程

2.1 进程的创建、启动和执行

在Windows中没有fork()调用,可以使用multiprocessing模块的Process类来创建进程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
"""多进程示例"""
from multiprocessing import Process
from os import getpid
from random import randint
from time import time, sleep

# 进程启动后要执行的代码
def download_task(filename):
print('启动下载进程,进程号[%d].' % getpid()) # 获取进程号
print('开始下载%s...' % filename)
time_to_download = randint(5, 10)
sleep(time_to_download)
print('%s下载完成!耗费了%d秒' % (filename, time_to_download))


def main():
start = time()

# 进程1,使用multiprocessing模块的Process类来创建子进程
# 参数target传入一个函数来表示进程启动后要执行的代码,args代表传递给target函数的参数
p1 = Process(target=download_task, args=('Python从入门到ICU.pdf', ))
p1.start() # 启动进程

# 进程2
p2 = Process(target=download_task, args=('Peking Hot.avi', ))
p2.start()

p1.join() # 等待进程执行结束
p2.join()

end = time()
print('总共耗费了%.2f秒.' % (end - start))


if __name__ == '__main__':
main()

1

2.2 进程间通信

使用multiprocessing模块的Queue类(底层通过管道和信号量实现)

3、Python中的多线程

Python-Day12-正则表达式

参考:

[正则表达式30分钟入门教程]: https://deerchao.cn/tutorials/regex/regex.htm

[Python - 100天从新手到大师]: https://github.com/jackfrued/Python-100-Days

1、笔记

  • 精确查找 hi 这个单词,使用 \bhi\b
  • 确保整个字符串就是5-12位数字,而不是字符串中包含 5-12连续位数字,使用 ^\d{5,12}$
  • 使用分支条件时,注意各个条件的顺序。因为匹配分枝条件时,将会从左到右地测试每个条件,如果满足了某个分枝的话,就不会去再管其它的条件了。
    • \d{5}-\d{4}|\d{5}这个表达式用于匹配美国的邮政编码(5位数字,或者用连字号间隔的9位数字)
    • \d{5}|\d{5}-\d{4}这个表达式就只会匹配5位的邮编(以及9位邮编的前5位)
  • 同时使用两种断言(?<=\s)\d+(?=\s)匹配以空白符间隔的数字(提醒:不包括这些空白符)
  • 反义总要匹配一个字符:
    • \b\w*q[^u]\w*\b本意是匹配包含后面不是字母u的字母q的单词,,但无法匹配q在结尾的情况。因为[^u]总要匹配一个字符,所以对于Iraq这个词,[^u]就匹配了\b,导致\w*\b匹配下一个单词,因此可能会匹配成整个 Iraq fighting
    • 解决办法:\b\w*q(?!u)\w*\b
  • 正则表达式最早开始的匹配拥有最高的优先权,其次是贪婪匹配
    • 对字符串 aabab,a.*b匹配aabab(贪婪匹配)
    • 对字符串 aabab,a.*?b匹配aab(最早开始的匹配,懒惰匹配)和ab(懒惰匹配)

2、正则表达式归纳

2.1 常用元字符 & 反义

语法 含义 示例 说明
元字符
. 匹配除换行符以外的任意字符 b.t 可以匹配bat / but / b#t / b1t等
\w 匹配字母/数字/下划线/汉字 b\wt 可以匹配bat / b1t / b_t / b汉t等
但不能匹配b#t
\s 匹配任意的空白字符(包括\r、\n、\t等) love\s\you 可以匹配love you
\d 匹配数字 \d\d 可以匹配01 / 23 / 99等
\b 匹配单词的边界(开始或结束) \bThe\b 匹配The apple中的The
^ 匹配字符串的开始 ^The 可以匹配The开头的字符串
$ 匹配字符串的结束 .exe$ 可以匹配.exe结尾的字符串
反义 反义总要匹配一个字符
\W 匹配任意非字母/数字/下划线/汉字的字符 b\Wt 匹配b#t / b@t等
不能匹配but / b1t / b_t/ b汉t等
\S 匹配非空白字符 love\Syou 匹配love#you等
但不能匹配love you
\D 匹配非数字 \d\D 匹配9a / 3# / 0F等
\B 匹配非单词边界(不是单词开头或结束的位置) \Bio\B 匹配lion中的io
  • 若查找元字符本身,使用字符转义符\,eg. \\, \*, \., \(, \)
  • 精确查找 hi 这个单词,使用 \bhi\b
  • 确保整个字符串就是5-12位数字,而不是字符串中包含 5-12连续位数字,使用 ^\d{5,12}$

2.2 重复限定符 & 懒惰限定符

语法 含义 示例 说明
重复限定符
* 匹配0次或多次 \w*
+ 匹配1次或多次 \w+
? 匹配0次或1次 \w?
{n} 匹配n次 \w{5} 可以匹配 enhhh / 你是个憨批 等
{n,} 匹配至少n次 \w{3,}
{n,m} 匹配至少n次至多m次 \w{3,6} 匹配3-6位连续的字母/数字/下划线/汉字
懒惰限定符
*? 重复任意次,但尽可能少重复 a.*b
a.*?b
匹配aabab的aabab
匹配aabab的aab和ab
+? 重复1次或多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复

正则表达式最早开始的匹配拥有最高的优先权,其次是贪婪匹配

  • 对字符串 aabab,a.*b匹配aabab(贪婪匹配)
  • 对字符串 aabab,a.*?b匹配aab(最早开始的匹配,懒惰匹配)和ab(懒惰匹配)

2.3 字符类

语法 含义 示例 说明
[] 匹配来自字符集的任意单一字符 [aeiou]
[a-z0-9A-Z]
匹配任一元音字母字符
匹配一个大小写字母/数字
[^] 匹配不在字符集中的任意单一字符 ^ 匹配任一非元音字母字符

2.4 分支

语法 含义 示例 说明
branch0 分支 branch 可以匹配foo或者bar
  • 使用分支条件时,注意各个条件的顺序。因为匹配分枝条件时,将会从左到右地测试每个条件,如果满足了某个分枝的话,就不会去再管其它的条件了。
    • \d{5}-\d{4}|\d{5}这个表达式用于匹配美国的邮政编码(5位数字,或者用连字号间隔的9位数字)
    • \d{5}|\d{5}-\d{4}这个表达式就只会匹配5位的邮编(以及9位邮编的前5位)

2.5 分组/后向引用/断言/注释

  • 分组0对应整个正则表达式,\1代表分组1匹配的文本
语法 含义 示例 说明
捕获
(exp) 匹配exp,并捕获文本到自动命名的组里 \b(\w+)\b\s+\1\b 可以匹配go go / kitty kitty等重复单词
\1代表分组1匹配的文本
(?<name>exp) 匹配exp,并捕获文本到名为name的组中,也可以写成(?'name'exp) \b(?\w+)\b\s+\k\b 匹配内容同上
\k<Word>用来反向引用分组捕获内容
(?:exp) 匹配exp,但是不捕获匹配的文本,也不给此分组分配编号
零宽断言
(?=exp) 匹配exp前面的位置 \b\w+(?=ing) 可以匹配I’m dancing中的danc
(?<=exp) 匹配exp后面的位置 (?<=\bdanc)\w+\b 可以匹配I love dancing and reading中的第一个ing
负向零宽断言
(?!exp) 匹配后面跟的不是exp的位置
(?<!exp) 匹配前面不是exp的位置
注释
(?#comment) 注释,这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读
  • 同时使用两种零宽断言(?<=\s)\d+(?=\s)匹配以空白符间隔的数字(提醒:不包括这些空白符)
  • 负向零宽断言用于确保某个字符没有出现,但不想去匹配它
    • \b\w*q[^u]\w*\b本意是匹配包含后面不是字母u的字母q的单词,,但无法匹配q在结尾的情况。因为[^u]总要匹配一个字符,所以对于Iraq这个词,[^u]就匹配了\b,导致\w*\b匹配下一个单词,因此可能会匹配成整个 Iraq fighting
    • 解决办法:负向零宽断言\b\w*q(?!u)\w*\b
  • 注释(?#comment)2[0-4]\d(?#200-249)|25[0-5](?#250-255)|[01]?\d\d?(?#0-199)表示IP地址中的一个数字,不能大于255

3、Python对正则表达式的支持

Python提供了re模块来支持正则表达式相关操作。re模块的核心函数如下表所示:

函数 说明
compile(pattern, flags=0) 编译正则表达式返回正则表达式对象
match(pattern, string, flags=0) 用正则表达式匹配字符串 成功返回匹配对象 否则返回None
search(pattern, string, flags=0) 搜索字符串中第一次出现正则表达式的模式 成功返回匹配对象 否则返回None
split(pattern, string, maxsplit=0, flags=0) 用正则表达式指定的模式分隔符拆分字符串 返回列表
sub(pattern, repl, string, count=0, flags=0) 用指定的字符串替换原字符串中与正则表达式匹配的模式 可以用count指定替换的次数
fullmatch(pattern, string, flags=0) match函数的完全匹配(从字符串开头到结尾)版本
findall(pattern, string, flags=0) 查找字符串所有与正则表达式匹配的模式 返回字符串的列表
finditer(pattern, string, flags=0) 查找字符串所有与正则表达式匹配的模式 返回一个迭代器
purge() 清除隐式编译的正则表达式的缓存
re.I / re.IGNORECASE 忽略大小写匹配标记(用于flags赋值)
re.M / re.MULTILINE 多行匹配标记(用于flags赋值)
  • re模块的正则表达式相关函数中都有一个flags参数,它代表了正则表达式的匹配标记,可以通过该标记来指定匹配时是否忽略大小写、是否进行多行匹配、是否显示调试信息等。如果需要为flags参数指定多个值,可以使用按位或运算符进行叠加,如flags=re.I | re.M
  • re.match(pattern, string, flags=0),匹配
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
"""
验证输入用户名和QQ号是否有效并给出对应的提示信息

要求:
- 用户名必须由字母、数字或下划线构成且长度在6~20个字符之间
- QQ号是5~12的数字且首位不能为0
"""

import re

def main():
username = input('请输入用户名:')
qq = input('请输入QQ号:')

# match函数的第一个参数是正则表达式字符串或正则表达式对象
# 第二个参数是要跟正则表达式做匹配的字符串对象
m1 = re.match(r'^[0-9a-zA-Z_]{6,20}$', username)
if not m1:
print('请输入有效的用户名!')

m2 = re.match(r'^[1-9]\d{4,11}$', qq) # 字符串前加上r表示原始字符串,即字符串中每个字符都有原始意义,不含转义字符。否则\d要写成\\d
if not m2:
print('请输入有效的QQ号!')

if m1 and m2:
print('你输入的信息是有效的!')

if __name__ == '__main__':
main()
  • re.compile(pattern, flags=0),编译正则表达式,并创建正则表达式对象
  • re.findall(pattern, string, flags=0), 返回列表
  • pattern.finditer(pattern, string, flags=0),返回迭代器
  • pattern.search(pattern, string, flags=0)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
"""
从一段文字中提取出国内手机号码

电信:133/153/180/181/189/177
联通:130/131/132/155/156/185/186/145/176
移动:134/135/136/137/138/139/150/151/152/157/158/159/182/183/184/187/188/147/178
即130-139, 145, 147, 150-153, 155-159, 176-178, 180-189
"""

import re

def main():
# re.compile(pattern, flags=0),编译正则表达式,并创建正则表达式对象
# 使用了前瞻断言(?<=\D)和回顾断言(?=\D)来保证手机号前后不应该出现数字
# 也可以使用前瞻和回顾负向断言:(?<!\d)和(?!\d)
pattern = re.compile(r'(?<=\D)(1[38]\d{9}|14[57]\d{8}|15[0-35-9]\d{8}|17[6-8]\d{8})(?=\D)')

sentence = '''
重要的事情说8130123456789遍,我的手机号是13512346789这个靓号,
不是15600998765,也不是110或119,王大锤的手机号才是15600998765
'''

# re.findall(pattern, string, flags=0), 返回列表
# 查找所有匹配,并保存到一个列表中
mylist = re.findall(pattern, sentence)
print(mylist)
print('--------华丽的分割线--------')

# pattern.finditer(pattern, string, flags=0),返回迭代器
# 通过迭代器取出匹配对象,并获得匹配的内容
for temp in pattern.finditer(sentence):
print(temp.group())
print('--------华丽的分割线--------')

# pattern.search(pattern, string, flags=0)
# 通过search函数指定搜索位置,找出所有匹配项
m = pattern.search(sentence)
while m:
print(m.group)
m = pattern.search(sentence, m.end())


if __name__ == '__main__':
main()

exercise2

  • re.sub(pattern, repl, string, count=0, flags=0),替换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
"""
替换字符串中的不良内容
"""

import re

def main():
sentence = '你丫是傻叉吗? 我操你大爷的. Fuck you.'
purified = re.sub('[操肏艹]|fuck|shit|傻[比屄逼叉缺吊屌]|煞笔',
'*', sentence, flags=re.IGNORECASE)
print(purified) # 你丫是*吗? 我*你大爷的. * you.


if __name__ == '__main__':
main()
  • re.split(pattern, string, maxsplit=0, flags=0),字符串切割
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
"""
拆分长字符串
"""

import re

def main():
poem = '床前明月光,疑是地上霜。举头望明月,低头思故乡。'

sentence_list = re.split(r'[,。,.]', poem)
while '' in sentence_list:
sentence_list.remove('')
print(sentence_list)
# ['床前明月光', '疑是地上霜', '举头望明月', '低头思故乡']


if __name__ == '__main__':
main()

用GitHub Pages和Hexo架搭建博客

参考了如下教程:

[超全面!如何用 GitHub 从零开始搭建一个博客 ?]: https://url.cn/5xQgPFy

[用 GitHub + Hexo 建立你的第一个博客]: https://url.cn/5iCNSb6

1、在GitHub上建立仓库

首先需要有GitHub账号

在GitHub新建一个仓库(Repository),名称为 {username}.github.io ,注意这个名称必须是 github.io 结尾。比如我的GitHub用户名为 PanosPanay ,我就新建一个 PanosPanay.github.io 。

new-repository

create-repository

2、搭建环境

2.1 安装Node.js

下载地址:https://nodejs.org/zh-cn/download/

按照提示安装即可。

正常安装完成后,环境变量就已经被配置好了,能正常使用npm命令。可以在桌面按住Shift键,鼠标右键在此处打开PowerShell(命令行)窗口(或者cmd打开命令行;或者右键Git Bash Here打开命令行),依次输入如下命令,分别出现对应版本号代表安装成功。

1
2
node -v
npm -v

nodejs

2.2 安装Hexo

打开命令行,输入如下命令回车,等待安装。

1
2
cd /	# 返回C盘根目录,这一条命令是否使用看个人习惯,在这里可省略
npm install hexo-cli -g

安装过程中可能有一些WARN,可以不用管,之后的步骤能正常使用hexo即表示安装配置成功。

3、初始化博客/项目

这一步通过Hexo命令创建一个项目,并将其在本地跑起来。

首先,在任意位置新建一个文件夹,我在C盘新建了Blog文件夹。

然后,打开新建的文件夹(C:\Blog),右键Git Bash Here;或者在此处打开PowerShell;或者在打开的命令行中通过cd指令定位到刚才新建的文件夹。

hexo-init-prepare

然后,使用如下命令创建项目:

1
hexo init panospanay	# init之后跟的是项目名称,即要创建的博客名称

上述命令执行后会在C:\Blog文件夹中生成panospanay文件夹,且该文件夹下包含了Hexo的初始化文件。

然后,在命令行中通过cd指令转到panospanay文件夹(cd C:\Blog\panospanay);或者打开panospanay文件夹后在此打开命令行/Git Bash Here,输入如下指令,将Hexo编译成HTML代码。

1
hexo generate

然后,运行如下命令:

1
hexo server

运行以上命令后,命令行出现如下提示:

1
2
INFO  Start processing
INFO Hexo is running at http://localhost:4000 . Press Ctrl+C to stop.

此时,打开浏览器,输入地址 http://localhost:4000 ,就可以看到最原始的博客。我我当时没有截图,从参考的教程中截了一张图,大概是这样的:

init-blog

到这里,博客的雏形就完成了。之后对博客进行各种配置改动,或者发布新博文,也可以通过hexo server在本地运行,浏览器输入 http://localhost:4000 预览。

4、部署博客

这一步将初始化的博客部署到GitHub Page。

首先,打开根目录(项目的根目录即panospanay文件夹),用VS Code打开_config.yml文件,找到Deployment部分,将第一步在GitHub新建的仓库地址粘贴过来,修改如下:

deployment

然后,额外安装一个支持 Git 的部署插件,名字叫做 hexo-deployer-git,在panospany文件夹下打开命令行(后面无特殊说明都在此位置运行命令行),执行如下命令:

1
npm install hexo-deployer-git --save

安装成功后,继续执行以下部署命令:

1
hexo deploy

执行以上命令后,命令行出现类似如下提示,说明部署成功:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
INFO  Deploying: git
INFO Clearing .deploy_git folder...
INFO Copying files from public folder...
INFO Copying files from extend dirs...
On branch master
nothing to commit, working directory clean
Counting objects: 46, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (36/36), done.
Writing objects: 100% (46/46), 507.66 KiB | 0 bytes/s, done.
Total 46 (delta 3), reused 0 (delta 0)
remote: Resolving deltas: 100% (3/3), done.
To git@github.com:NightTeam/nightteam.github.io.git
* [new branch] HEAD -> master
Branch master set up to track remote branch master from git@github.com:NightTeam/nightteam.github.io.git.
INFO Deploy done: git

此时即可访问和Github Repository同名的链接来打开博客,比如我的仓库名称为panospanay.github.io,我访问 https://panospanay.gihub.io/ 即可打开博客,与第3步本地运行打开 http://localhost:4000 预览到的博客内容一致。

注意,在第一次打开 https://panospanay.gihub.io/ 这个链接时可能出现404,但之后重新打开就可以了,而且https和http都可以打开。

打开GitHub仓库转到master分支,可以看到Hexo上传了如下内容,实际上就是博客文件夹下面的 public 文件夹下的所有内容,Hexo 把编译之后的静态页面内容上传到 GitHub 的 master 分支上面去了。

github-master

然后,通过执行如下命令,新建一个source分支,用来存储博客源码到GitHub。

1
2
3
4
5
6
git init
git checkout -b source
git add -A
git commit -m "init blog"
git remote add origin git@github.com:{username}/{username}.github.io.git
git push origin source

执行成功后,可以到GitHub上切换默认分支为source,不过也可以不切换。

branches1

change-default-page1

change-default-page2

5、配置站点信息

这一步进行博客的基本配置,包括主题和一些其他内容。

5.1 修改博客站点基本配置

VS Code打开根目录(panospanay文件夹)下的 _config.yml 文件,找到 Site 区域,配置如下信息:

site

6、修改主题

主题配置,这里我使用的是Next主题。

首先,在themes文件夹下建立next文件夹。

在根目录下,通过命令行中执行如下命令,执行完毕后Next主题就会出现在themes/next 文件夹下。

1
git clone https://github.com/theme-next/hexo-theme-next themes/next

然后,打开根目录下的 _config.yml 文件,找到 theme 字段,修改为 next 即可。

theme-next

然后在命令行中执行hexo server开启本地服务,浏览器输入 http://localhost:4000 即可预览博客更改。

1
hexo server

muse

7、主题配置

针对Next主题,还可以进行更详细的配置。

主题配置需要修改的配置文件是 themes/next 文件夹下的 _config.yml ,用VS Code打开 themes/next/_config.yml 文件。以下若未特别强调都是指,配置文件指的都是在这个文件。

7.1 样式

修改 scheme 的值可以更改布局样式。我选择的是Pisces样式。

scheme

默认的Muse样式见第6步的图

Mist样式:

mist

Pisces似乎和Gemini看不出区别:

pisces

7.2 favicon

favicon是站点在浏览器标签栏的图标,默认是Hexo的小图标:

favicon1

可以在网站 https://realfavicongenerator.net 上传自己的图片,进行转换,打包下载适配各种尺寸和不同设备的小图标。将这些图标拷贝到 themes/next/source/images 文件夹中。

然后在配置文件中找到 favicon 配置项,修改如下:

favicon2

配置后战点图标如下:

favicon3

7.3 avatar

avatar是显示在作者信息旁的头像。

将自己喜爱的头像图片 avatar.gif (也可以是其他格式的图片,eg. png)放置到 themes/next/source/images 文件夹,然后在配置文件中找到avatar配置项,修改如下:

avatar

修改后效果图如下:

avatar2

7.4 rss

安装 hexo-generator-feed ,可开启站点SSR订阅。在项目根目录下,即 panospanay 文件夹中打开命令行,运行如下命令。

7.5 code

代码块的修改,修改配置文件如下:

code

配置后效果图:

code2

7.6 top

快速返回网站顶端按钮,修改配置文件如下:

back2top

效果图:

top

7.7 reading_process

阅读进度,站点顶部进度条。修改配置文件如下:

reading-process

效果图:

reading

7.9 bookmark

书签,可以在下次打开页面的时候快速定位到上次的位置。修改配置文件如下:

bookmark

效果图:

bookmark2

7.10 github_banner

在博客页面右上角显示 GitHub 图标,点击之后可以跳转到源代码页面。修改配置文件如下:

github-banner

效果图:

github-banner2

7.11 gittalk

第三方评论功能,gittalk利用GitHub 的 Issue 来当评论

首先,打开链接 https://github.com/settings/applications/new 注册一个 OAuth Application:

oauth

点击注册后会看到Client ID、Client Secret。

在配置文件中修改comments配置:

comments

继续在配置文件中修改gittalk配置:

gittalk

效果图(已使用GitHub授权登录):

gittalk2

7.12 pangu

开启此选项,在编译生成页面的时候,中英文之间会自动添加空格,使得排版更美观。

修改配置文件如下:

pangu

效果图:

pangu2

7.13 math

Next主题提供了两个公式渲染引擎,分别是 mathjax 和 katex,后者相对前者来说渲染速度更快,而且不需要 JavaScript 的额外支持,但后者支持的功能现在还不如前者丰富。所以这里选择的是mathjax。

修改配置文件如下:

math

还需要在用到数学公式md文件的Front-matter里打开mathjax开关,如下面代码的末尾所示:

1
2
3
4
5
6
7
8
9
10
11
---
title: deeplearning.ai_C2W2_optimization_algorithms
date: 2020-03-07 19:58:55
tags:
- deeplearning
- 吴恩达
- 深度学习
categories:
- 深度学习
mathjax: true
---

之所以在文章头里设置开关mathjax: true,是因为只有使用了公式的md文件的显示才需要加载 Mathjax,其他md文件的渲染页面速度不受影响。

7.14 pjax

利用 Ajax 技术实现了局部页面刷新,既可以实现 URL 的更换,又可以做到无刷新加载。

首先,修改配置文件如下:

pjax

然后切换到 next 目录下,运行如下命令,安装依赖库:

1
2
cd themes/next
git clone https://github.com/theme-next/theme-next-pjax source/lib/pjax

7.15 其他

Next主题的其他设置可以参考官方文档: https://theme-next.org/docs/

8、文章/博文

关于如何发布新博文,可以参考《新建文件》https://panospanay.github.io/2019/11/20/test_new/

在根目录下,调用命令行(/ Git Bash),执行如下命令:

1
hexo new 文件名

比如,我要新建名为 “test.md” 的文章,则执行命令:

1
hexo new test

执行后,创建的文章会出现在 source/_posts 文件夹下,是 MarkDown 格式。

然后,打开创建的 “test.md” 文件,在文章开头通过如下格式添加必要信息:

1
2
3
4
5
6
7
8
9
10
11
---
title: 标题 # 自动创建,可修改,与文件名不同,是显示在博客上的标题
date: 日期 # 自动创建,eg.2019-11-20 23:13:18
tags:
- 标签1 # 注意'- 标签'之间的空格,漏写空格会导致博客更新不上去
- 标签2
- 标签3
categories:
- 分类1
- 分类2
---

然后在下方用markdown格式编辑博客即可。

8.1 上传图片到博客

如果博客/markdown文件中要显示图片,需要进行如下操作:

首先,在项目的配置文件(注意是博客根目录下的 _config.yml 文件)中找到 post_asset_folder 字段,修改如下:

image-folder

然后,在博客的根目录下执行如下指令:

1
npm install https://github.com/CodeFalling/hexo-asset-image --save

执行上述操作后,在建立文件(Hexo new 文件名)时,Hexo 会自动建立一个与文章同名的文件夹,我们可以把与该文章相关的所有资源(包括图片)都放到此文件夹内,这样就可以更方便的使用资源。

验证一下,在根目录下执行以下命令:

1
hexo new github-blog

可以看到此时source/_posts 目录下生成github-blog文件夹和github-blog.md文件:

image1

然后,将写博文所需的图片放到生成的github-blog文件夹(博文同名文件夹)下:

image2

然后,在博文中用如下格式插入图片:

image3

9、标签页和分类页

当前博客只有首页和归档,可以给博客添加标签页和分类页

9.1 标签页

在根目录(C:\Blog\panospanay)执行如下命令:

1
hexo new page tags

执行命令后自动生成 source/tags/index.md 文件,内容如下:

1
2
3
4
---
title: tags
date: 2019-11-20 23:16:47
---

我们可以自行添加一个 type 字段来指定页面的类型:

1
2
type: tags
comments: false

然后,在主题配置文件 _config.yml 中修改menu字段,将这个页面的链接添加到主菜单里面:

tags

9.2 分类页

在根目录(C:\Blog\panospanay)执行如下命令:

1
hexo new page categories

执行命令后自动生成 source/categories/index.md 文件,内容如下:

1
2
3
4
---
title: categories
date: 2019-11-20 23:18:59
---

我们可以自行添加一个 type 字段来指定页面的类型:

1
2
type: categories
comments: false

然后,在主题配置文件 _config.yml 中修改menu字段,将这个页面的链接添加到主菜单里面:

categories

最后的效果:

tag2

10、搜索页

首先,在根目录运行如下命令,安装 hexo-generator-searchdb 插件。

1
npm install hexo-generator-searchdb --save

然后,在项目的配置文件(注意是根目录下的 _config.yml 文件),在最下面添加如下配置:

search

然后,在主题的配置文件(themes/next/_config.yml 文件),修改配置文件如下:

search1

效果图如下,可以对全站的博客内容进行搜索:

search2

11、404页面

还需要添加一个 404 页面,直接在根目录的 source 文件夹中新建一个 404.md 文件即可。

404

文件的内容可以参考如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
---
title: 404 Not Found
date: 2019-11-20 23:26:26
---

<center>
对不起,您所访问的页面不存在或者已删除。
您可以<a href="https://panospanay.github.io/">点击此处</a>返回首页。
</center>

<blockquote class="blockquote-center">
良多
</blockquote>

12、 Hexo的其他配置

参考官方文档:https://hexo.io/zh-cn/docs/ 查看更多的配置。

12、 部署脚本

首先,在根目录下新建一个deploy.sh脚本文件,内容如下:

1
2
3
hexo clean
hexo generate
hexo deploy

然后,每次要发布的时候我们只要在根目录执行如下命令,即可完成博客的更新:

1
sh deploy.sh

至此,我们有了2种博客更新查看方式:

  • 在对博客进行配置更改或者编辑修改博文时,可以在根目录执行如下指令打开本地服务器,然后浏览器打开链接 http://localhost:4000 ,即可实时查看预览:
1
hexo server
  • 在我们完成配置或者博文增改,确认要发布时,可以在根目录执行如下指令,即可部署发布,部署成功后,浏览器打开链接 https://panospanay.gihub.io/ 即可打开博客查看更新。不过有时候更新可能需要一段时间。
1
sh deploy.sh

13、 自定义域名

自定义域名是需要自己先购买域名的,因此没有购买域名的可以跳过这一步。

申请域名可以使用Freenom,网站链接 https://my.freenom.com/domains.php ,提供最多一年的免费顶级域名。

在 GitHub 的 Repository 里,找到 Settings,拉到下面,可以看到有个 GitHub Pages 的配置项,如图所示:

cname

首先,填好上面的域名地址。此时上图的绿色提示部分可能出现红色报错。因为我们还没有添加CNAME解析。刚配置完自定义域名的时候可能 Enforce HTTPS 这个选项是不可用的,一段时间后等到其可以勾选了,直接勾选即可,这样整个博客就会变成 HTTPS 的协议的了。

然后,在source目录下新建一个 CNAME 文件(没有后缀),文件内容就是你的域名地址。

部署发布之后,就配置好了。

如果有未购买域名的小伙伴执行了上面的操作,发现删除了CNAME文件,清空了GitHub仓库设置里的域名地址,可是访问博客仍然会跳转到原来自定义的域名,这是因为chrome浏览器缓存问题,可换个浏览器或者过段时间再访问即可成功。