MachineLearning

监督式学习

指目标给定标签来进行分类等例如聚类,分类问题等

无监督式学习

指目标没有指定的标签,通过已有样本的特点来进行预测拟合,如回归分析

构成

  1. 代价函数(一般为平方差等,表示拟合量与实际值的偏差)通过寻找代价函数与目标函数参数关系寻找到最小值来进行回归。

  2. 梯度下降法,通过遍历寻找在当前点梯度最大方向进行遍历,类似于贪心的思想,来降低代价函数值寻找局部最小值(注意,这里并不是全局的最小值),越大的学习系数每一步的步长越长,需要注意的是每次要做到每个系数的同步跟新。
    通过画出代价函数变化函数来确定是否收敛,一般在学习速率够小时,代价函数都会随着迭代而减小,但过小会导致收敛速度慢的问题

  3. 反向传播:包含两个阶段,激励传播与权重更新

    • 激励传播:包含两步,第一步前向传播阶段,将输入送入网络获得激励响应;第二部,求出代价函数,一般为方差获得输出层和隐藏层的误差
    • 权重更新:根据代价函数对于不同权重敏感程度以及各个激活值距离正确值的大小来决定,例如在有两个神经元一个激活值为0.2其期望值是1,一个是0.3其期望值是0,那么需要优先调整距离期望较大的神经元

TensorFlow2.x学习笔记

基础

创建变量等操作与1.x基本类似,但可以进行即时执行模式,与之前的图执行模式不同,语法更精炼简单。

num_epoch = 100000
optimizer = tf.keras.optimizers.SGD(learning_rate = 5e-4)
for e in range(num_epoch):
    with tf.GradientTape() as tape:
        y_pred = a * x + b
        loss = tf.reduce_sum(tf.square(y - y_pred))
    grads = tape.gradient(loss , variables)
    optimizer.apply_gradients(grads_and_vars = zip(grads , variables))

可以直接调用GradientTape来进行梯度以及导数计算。上面的代码中声明了一个梯度下降优化器,可以通过计算的求导结果更新模型参数,从而最小化某个特定的损失函数,通过apply_gradients()方法来进行调用,函数内的参数为需要更新的变量以及损失函数关于该变量的偏导数。需要传入一个列表,每个元素为(偏导,变量)。

模型与层

使用TF内置的库Keras来进行模型的构建。
Keras里有两个重要的概念:层(Layer)模型(model),层将各种计算流程和变量进行了封装(全连接层,卷积层,池化层等),模型则用于各种层进行连接。模型通过类的形式呈现,所以可以通过继承tf.keras.Model来定义自己的模型,需要重写init()和call(),继承模型后可以调用模型中的方法和属性。可以大量简化代码,下面是通过模型的方式编写的一个简单的线性回归,可以看出在进行计算处理部分与之前基本一致,但是关于模型变量的访问,以及模型初始化都方便了许多。通过在模型内部实例化了一个全连接层,并对其在call()中进行调用

X = tf.constant([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
y = tf.constant([[10.0], [20.0]])

class Linear(tf.keras.Model):
    def __init__(self):
        super().__init__()
        self.dense = tf.keras.layers.Dense(
            units = 1,
            activation=None,
            kernel_initializer = tf.zeros_initializer(),
            bias_initializer = tf.zeros_initializer()
        )
    def call(self , input):
        output = self.dense(input)
        return output
model = Linear()
optimizer = tf.keras.optimizers.SGD(lr=0.01)
for i in range(100):
    with tf.GradientTape() as tape:
        y_pred = model(X)
        loss = tf.reduce_mean(tf.square(y_pred - y))
    grads = tape.gradient(loss , model.variables)
    optimizer.apply_gradients(grads_and_vars = zip(grads , model.variables))
print(model.variables)

全连接层(Dense) 是最常用的层之一,对输入矩阵进行f(AW+b)的线性变换+激活函数操作,激活函数一般是Relu等等.包含的参数如下

  • units 输出张量的维度
  • activation 激活函数 不指定时为f(x) = x
  • use_bias 添加偏置,默认为True
  • kernel_initializer,bias_initializer 权重,偏置的初始化器,默认为glort_uniform_initializer(很多层都默认使用),使用ezeros_initializer表示初始化为0

softmax函数为了使得模型的输出能始终满足这两个条件,我们使用 Softmax 函数 (归一化指数函数, tf.nn.softmax )对模型的原始输出进行归一化 。不仅如此,softmax 函数能够凸显原始向量中最大的值,并抑制远低于最大值的其他分量,这也是该函数被称作 softmax 函数的原因(即平滑化的 argmax 函数)。

模型的训练

tf.keras.losses 和 tf.keras.optimizer
需要定义一些模型超参数

  • num_epochs = 5

  • batch_size = 50

  • learning_rate = 0.001
    之后实例化模型和优化器,迭代进行数据的读取以及模型的训练步骤如下

  • 从 DataLoader 中随机取一批训练数据;

  • 将这批数据送入模型,计算出模型的预测值;

  • 将模型预测值与真实值进行比较,计算损失函数(loss)。这里使用 tf.keras.losses 中的交叉熵函数作为损失函数

  • 计算损失函数关于模型变量的导数;

  • 将求出的导数值传入优化器,使用优化器的 apply_gradients 方法更新模型参数以最小化损失函数

模型的评估

使用tf.keras.metrics中的SparseCategoricalAccuracy来评估模型在测试集上的性能,通过将预测结果与真是结果相比较,输出正确的占比。通过update_state()方法向评估器输入预测值和真实值。其内部有变量来保存当前评估的指标的数值,最终通过result()方法输出最终评估值。

代码汇总

import numpy as np
import tensorflow as tf
#CNN with keras
class CNN(tf.keras.Model):
    def __init__(self):
        super().__init__()
        self.conv1 = tf.keras.layers.Conv2D(
            filters=32,             # 卷积层神经元(卷积核)数目
            kernel_size=[5, 5],     # 感受野大小
            padding='same',         # padding策略(vaild 或 same)
            activation=tf.nn.relu   # 激活函数
        )
        self.pool1 = tf.keras.layers.MaxPool2D(pool_size=[2, 2], strides=2)
        self.conv2 = tf.keras.layers.Conv2D(
            filters=64,
            kernel_size=[5, 5],
            padding='same',
            activation=tf.nn.relu
        )
        self.pool2 = tf.keras.layers.MaxPool2D(pool_size=[2, 2], strides=2)
        self.flatten = tf.keras.layers.Reshape(target_shape=(7 * 7 * 64,))
        self.dense1 = tf.keras.layers.Dense(units=1024, activation=tf.nn.relu)
        self.dense2 = tf.keras.layers.Dense(units=10)

    def call(self, inputs):
        x = self.conv1(inputs)                  # [batch_size, 28, 28, 32]
        x = self.pool1(x)                       # [batch_size, 14, 14, 32]
        x = self.conv2(x)                       # [batch_size, 14, 14, 64]
        x = self.pool2(x)                       # [batch_size, 7, 7, 64]
        x = self.flatten(x)                     # [batch_size, 7 * 7 * 64]
        x = self.dense1(x)                      # [batch_size, 1024]
        x = self.dense2(x)                      # [batch_size, 10]
        output = tf.nn.softmax(x)
        return output
# MNISTLoader and MLP
class MNISTLoader():
    def __init__(self):
        mnist = tf.keras.datasets.mnist
        (self.train_data, self.train_label), (self.test_data, self.test_label) = mnist.load_data()
        # MNIST中的图像默认为uint8(0-255的数字)。以下代码将其归一化到0-1之间的浮点数,并在最后增加一维作为颜色通道
        self.train_data = np.expand_dims(self.train_data.astype(np.float32) / 255.0, axis=-1)      # [60000, 28, 28, 1]
        self.test_data = np.expand_dims(self.test_data.astype(np.float32) / 255.0, axis=-1)        # [10000, 28, 28, 1]
        self.train_label = self.train_label.astype(np.int32)    # [60000]
        self.test_label = self.test_label.astype(np.int32)      # [10000]
        self.num_train_data, self.num_test_data = self.train_data.shape[0], self.test_data.shape[0]

    def get_batch(self, batch_size):
        # 从数据集中随机取出batch_size个元素并返回
        index = np.random.randint(0, self.num_train_data, batch_size)
        return self.train_data[index, :], self.train_label[index]




# class MLP(tf.keras.Model):
#     def __init__(self, *args, **kwargs):
#         super().__init__(*args, **kwargs)
#         self._flatten = tf.keras.layers.Flatten()
#         self.dense1 = tf.keras.layers.Dense(units=100 , activation = tf.nn.relu)
#         self.dense2 = tf.keras.layers.Dense(units=10)
#     def call(self, inputs):
#         x = self._flatten(inputs)
#         x = self.dense1(x)
#         x = self.dense2(x)
#         output = tf.nn.softmax(x)
#         return output
num_epochs = 5
batch_size = 50
learning_rate = 0.001
model = CNN()
data_loader = MNISTLoader()
optimizer = tf.keras.optimizers.Adam(learning_rate = learning_rate)
num_batches = int(data_loader.num_train_data // batch_size * num_epochs)
for batch_index in range(num_batches):
    X , y = data_loader.get_batch(batch_size)
    with tf.GradientTape() as tape:
        y_pred = model(X)
        loss = tf.keras.losses.sparse_categorical_crossentropy(y_true=y , y_pred=y_pred)
        loss = tf.reduce_mean(loss)
        print("batch %d: loss %f"%(batch_index , loss.numpy()))
    grads = tape.gradient(loss , model.variables)
    optimizer.apply_gradients(grads_and_vars = zip(grads , model.variables))
sparse_categorical_accuracy = tf.keras.metrics.SparseCategoricalAccuracy()
num_batches = int(data_loader.num_test_data // batch_size)
for batch_index in range(num_batches):
    start_index , end_index = batch_index * batch_size , (batch_index + 1) * batch_size
    y_pred = model.predict(data_loader.test_data[start_index : end_index])
    sparse_categorical_accuracy.update_state(y_true = data_loader.test_label[start_index : end_index] , y_pred= y_pred)
print("test accuracy : %f"%sparse_categorical_accuracy.result())
#using Model for linear regression
# X = tf.constant([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
# y = tf.constant([[10.0], [20.0]])

# class Linear(tf.keras.Model):
#     def __init__(self):
#         super().__init__()
#         self.dense = tf.keras.layers.Dense(
#             units = 1,
#             activation=None,
#             kernel_initializer = tf.zeros_initializer(),
#             bias_initializer = tf.zeros_initializer()
#         )
#     def call(self , input):
#         output = self.dense(input)
#         return output
# model = Linear()
# optimizer = tf.keras.optimizers.SGD(lr=0.01)
# for i in range(100):
#     with tf.GradientTape() as tape:
#         y_pred = model(X)
#         print(model.variables)
#         loss = tf.reduce_mean(tf.square(y_pred - y))
#     grads = tape.gradient(loss , model.variables)
#     optimizer.apply_gradients(grads_and_vars = zip(grads , model.variables))
# print(model.variables)
# 1st the linear regression
# X_raw = np.array([2013, 2014, 2015, 2016, 2017], dtype=np.float32)
# y_raw = np.array([12000, 14000, 15000, 16500, 17500], dtype=np.float32)

# x = (X_raw - X_raw.min()) / (X_raw.max() - X_raw.min())
# y = (y_raw - y_raw.min()) / (y_raw.max() - y_raw.min())

# x = tf.constant(x)
# y = tf.constant(y)

# a = tf.Variable(initial_value = 0.)
# b = tf.Variable(initial_value = 0 , dtype = tf.float32)
# variables = [a,b]

# num_epoch = 100000
# optimizer = tf.keras.optimizers.SGD(learning_rate = 5e-4)
# for e in range(num_epoch):
#     with tf.GradientTape() as tape:
#         y_pred = a * x + b
#         loss = tf.reduce_sum(tf.square(y - y_pred))
#     grads = tape.gradient(loss , variables)
#     optimizer.apply_gradients(grads_and_vars = zip(grads , variables))
# print(a,b)

TensorFlow1.x学习笔记

debug

module ‘tensorflow’ has no attribute ‘Session’(已修复)

在新版本中Tensorflow 2.0版本中已经移除了Session这一模块,改换运行代码以及对于graph的语法皆以变化,语法近似pytorch

import tensorflow as tf
tf.compat.v1.disable_eager_execution()
config = tf.compat.v1.ConfigProto(allow_soft_placement=True)
sess= tf.compat.v1.Session(config=config)

建立一个简单的回归分析模型

  1. 首先使用placeholder为输入与输出创建占位符,同时为权重和截距创建合适的变量
x = tf.placeholder(tf.float32 , shape = [None ,3]) #输入
y_ture = tf.placeholder(tf.float32 , shape = None) #实际值
w = tf.Variable([[0,0,0]] , dtype = tf.float32 , 
name = 'weights')  #权重
b = tf.Variable(0 , dtype = tf.float32 , name = 'bias') #截距
y_pred = tf.matmul(w , tf.transpose(x)) + b #预测值
  1. 接下来,需要来评估模型的性能,为了刻画预测值与真实值的差异,需要订一个反应“距离”的度量,一般称为损失函数,通过寻找一组参数来最小化损失函数优化模型。一般使用MSE(均方差)和交叉熵
#-----------------MRE
loss = tf.reduce_mean(tf.square(y_ture - y_pred)) #MSE
#----------------交叉熵
loss = tf.nn.sigmod_cross_entropy_with_logits(lables = y_ture , logits = y_pred)
loss = tf.reduce_mean(loss)
  1. 接下来需要明白如何最小化损失函数,一般使用梯度下降法,尽管可能陷入局部最优,但是一般都是足够好的。

  2. 由于计算整个样本集合可能会很慢,所以需要使用一些采样方法,对样本的子集进行采样,一般规模在50~500个一次,过小的样本会使得硬件利用率降低,而且会使得目标函数产生较大的波动,但有时波动也是有益的,因为能够使得参数跳跃到新的局部最优值,TF中通过向图中添加新的操作然后使用自动差分来计算梯度,需要设置的就是学习率,来确定每次更新迭代的量,一般更倾向于设置较小的学习率,以防止跳过了局部最优解,但过低会导致损失函数减少的十分慢。

optimizer = tf.train.GradientDsecentOptimizer(learning_rate)
train = optimizer.minimize(loss)

线性回归

使用numpy生成数据,创建了三个特征向量样本,每个样本内积乘以一组权重加上偏差项再加上噪声得出结果,通过优化模型找到最佳参数


import numpy as np
import tensorflow.compat.v1 as tf
tf.disable_eager_execution()
x_data = np.random.randn(2000 , 3)
w_real = [0.3 , 0.5 , 0.1]
b_real = -0.2

noise = np.random.randn(1,2000)*0.1
y_data = np.matmul(w_real , x_data.T) + b_real + noise
#生成数据
NUM_STEPS = 11
wb = []
g = tf.Graph()
with g.as_default():
    x = tf.placeholder(tf.float32 , shape = [None , 3])
    y_true = tf.placeholder(tf.float32 ,shape=None)
    with tf.name_scope('inference') as scope:
        w = tf.Variable([[0,0,0]] , dtype = tf.float32 , name = 'weights')
        b = tf.Variable(0 , dtype = tf.float32 , name = 'bias')
        y_pred = tf.matmul(w , tf.transpose(x)) + b

    with tf.name_scope('loss') as scope:
        loss = tf.reduce_mean(tf.square(y_true - y_pred))

    with tf.name_scope('train') as scope:
        learning_rate = 0.5
        optimizer = tf.train.GradientDescentOptimizer(learning_rate)
        train = optimizer.minimize(loss)

    init = tf.global_variables_initializer()
    with tf.Session() as sess:
        sess.run(init)
        for step in range(NUM_STEPS):
            sess.run(train,feed_dict={x :x_data , y_true : y_data})
            if step % 5 == 0:
                print(step , sess.run([w,b]))
                wb.append(sess.run([w,b]))

逻辑回归

一般用来进行二分类任务,输出一个0-1之间地离散二值结果,通过sigmoid函数来将数值映射到0到1之间,之后通过阈值分类器来将0到1之间的值转换为0或1,与之前代码的唯一不同是损失函数部分

with tf.name_scope('loss') as scope:
loss = tf.nn.sigmoid_cross_entropy_with_logits(labels = y_true , logits = y_pred)
loss = tf.reduce_mean(loss)

参数

CNN

层中的神经元只与前一层中的一小块区域连接,而不是采取全连接方式,主要由输入层,卷积层,ReLU层,池化层和全连接层构成(一般将卷积层和ReLU层一起称为卷积层)具体说来,卷积层和全连接层(CONV/FC)对输入执行变换操作的时候,不仅会用到激活函数,还会用到很多参数,即神经元的权值w和偏差b;而ReLU层和池化层则是进行一个固定不变的函数操作。卷积层和全连接层中的参数会随着梯度下降被训练,这样卷积神经网络计算出的分类评分就能和训练集中的每个图像的标签吻合了。

卷积层

参数由一些可学习的滤波器集合构成,只观察输入数据中的一小部分,由于卷积有“权值共享”这样的特性,可以降低参数的数量,防止参数过多造成过拟合。每个神经元连接的空间大小叫做神经元的感受野,深度与输入相同,但宽高是局部的。输出数据体和使用的滤波器的数量一致,将沿着深度方向排列。有时候在输入数据体的边缘使用0进行填充,使得滤波器可以平滑地在数据上滑动,一般是用来保持数据体的空间尺寸使输入输出宽高相同。如果在一个深度切片中的所有权重都使用同一个权重向量,那么卷积层的前向传播在每个深度切片中可以看做是在计算神经元权重和输入数据体的卷积(这就是“卷积层”名字由来)。这也是为什么总是将这些权重集合称为滤波器(filter)(或卷积核(kernel)),因为它们和输入进行了卷积。简单来说,就是一个在原始数据上以步长为长度不断移动的一个矩阵,层数与原始数据一致,将每个对应位置的数据进行乘积并且将每层的值相加,即为输出的一个数据,例如RGB通道下就是三层滤波器所得相加填入新的矩阵当中。

池化层

用来简化数据,减少计算量,有最大池化和平均池化,使用较多的是最大池化,通过找出某一个区域内的最大值/平均值来缩小数据,一般使用的参数是f=2,p=2 恰好为缩小数据为原来的一半,并且反向传播没有参数适用于池化,这一过程是静态过程,参数都是手动设定,或是交叉验证得到的,只用于简化数据,提取特征。

全连接层

将池化层简化后的数据进行提取,将特征整合到一起,输出为一个值,主要作用是减小特征位置对于结果产生的影响,将结果进行分类,一般不止一层,需要将提取出来的特征神经元激活后,通过不同神经元激活的组合,再提取出结果

简单的卷积实现mnist识别,将测试过程分为每个大小为1000幅图的十块

import tensorflow.compat.v1 as tf
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data
DATA_DIR = '/tmp/data'
NUM_STEPS = 10000
MINIBATCH_SIZE = 100
tf.disable_eager_execution()
def weight_variable(shape):
    initial = tf.truncated_normal(shape , stddev=0.1)
    return tf.Variable(initial)
def bias_variable(shape):
    initial = tf.constant(0.1 , shape = shape)
    return tf.Variable(initial)
def conv2d (x , w):
    return tf.nn.conv2d(x , w , strides = [1, 1 ,1 ,1] , padding = 'SAME')
def max_pool_2x2(x):
    return tf.nn.max_pool(x , ksize = [1 , 2, 2,1], strides = [1,2,2,1] , padding='SAME')
def conv_layer(input , shape):
    w = weight_variable(shape)
    b = bias_variable([shape[3]])
    return tf.nn.relu(conv2d(input,w)+b)
def full_layer(input , size):
    in_size = int(input.get_shape()[1])
    w = weight_variable([in_size,size])
    b = bias_variable([size])
    return tf.matmul(input,w) + b
x = tf.placeholder(tf.float32 , shape=[None , 784])
y_ = tf.placeholder(tf.float32 , shape=[None , 10])
x_image = tf.reshape(x,[-1,28,28,1])
conv1 = conv_layer(x_image , shape = [5,5,1,32])
conv1_pool = max_pool_2x2(conv1)

conv2 = conv_layer(conv1_pool , shape = [5,5,32,64])
conv2_pool = max_pool_2x2(conv2)

conv2_flat = tf.reshape(conv2_pool, [-1,7*7*64])
full_1 = tf.nn.relu(full_layer(conv2_flat , 1024))

keep_prob = tf.placeholder(tf.float32)
full1_drop = tf.nn.dropout(full_1 , keep_prob = keep_prob)

y_conv = full_layer(full1_drop , 10)

minst = input_data.read_data_sets(DATA_DIR , one_hot=True)
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits = y_conv , labels = y_) )
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_conv , 1) , tf.arg_max(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction , tf.float32))
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

    for i in range(NUM_STEPS):
        batch = minst.train.next_batch(50)

        if i % 100 == 0:
            train_accuracy = sess.run(accuracy , feed_dict={x:batch[0] , y_:batch[1] , keep_prob : 1.0})
            print("step {} , train accuracy {}".format(i,train_accuracy))
        sess.run(train_step , feed_dict={x:batch[0] , y_:batch[1] , keep_prob : 0.5})
        X = minst.test.images.reshape(10,1000,784)
        Y = minst.test.labels.reshape(10,1000,10)
        test_accuracy = np.mean([sess.run(accuracy , feed_dict={x:X[i] , y_:Y[i] , keep_prob : 1.0}) for i in range(10)])
    print("test accuracy: {}".format(test_accuracy))

ResNet

深度残差网络(Deep residual network, ResNet)的提出是CNN图像史上的一件里程碑事件.通过引入残差学习的方法来解决网络在随着深度增加时出现的准确度饱和下降,梯度爆炸以及消失的难以训练的问题。对于一个堆积结构,在输入x时,学到的特征为H(x),现在希望其学到残差即 H(x)-x,这样即使残差为0时,也仅是在层之间做了恒等映射,至少不会性能下降,残差使得其会在本有的特征上学习到新的特征,有点类似电路中的短路`

Mybatis

框架

  1. 框架的概念:软件开发中的一套解决方案,不同方案可以解决不同的问题,封装了许多的细节,可以使开发效率大幅度提高。
  2. 三层架构:
    • 表现层:数据的展示
    • 业务层:处理业务需求
    • 持久层:与数据库交互
  3. 持久层的技术解决方案
    • JDBC技术
      • Connection
      • PreparedStatement
      • ResultSet
    • Spring的JdbcTemplate:Spring对jdbc的简单封装
    • Apache的DBUtiles:与SPring的jdbcTemplate很像,也是对与jdbc的简单封装
  4. mybatis是一个持久层的框架,封装了jdbc操作的细节,使用了ORM思想,实现了结果集的封装。
    ORM(Object Relational Mapping)将数据库表和实体类及实体类的属性对应起来可以操作实体类就实现操作数据库表

环境搭建

  1. 使用IDE创建出一个maven项目

  2. 选择项目地打包方式,在项目中引入依赖

    <groupId>com.itheima</groupId>
     <artifactId>first_mybatis</artifactId>
     <version>1.0-SNAPSHOT</version>
     <packaging>jar</packaging>
     <dependencies>
         <dependency>
         <groupId>org.mybatis</groupId>
         <artifactId>mybatis</artifactId>
         <version>3.4.5</version>
     </dependency>
         <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
             <version>6.0.5</version>
         </dependency>
         <dependency>
             <groupId>log4j</groupId>
             <artifactId>log4j</artifactId>
             <version>1.2.12</version>
         </dependency>
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <version>4.12</version>
         </dependency>
     </dependencies>
  3. 接下来在src中创建数据库表中对应的对象,且要implements Serializable使对象序列化接下来是一些基本你的操作,将所有属性私有化留出get和set方法

  4. 接下来创建出一个IuserDao的接口(I的意思只是Interface)称为用户的持久层接口,在其中创建查询所有操作的序列。

  5. 配置mybtis的环境,创建一个xml文件在resources文件夹下,在创建完成后需要在相应的mapper位置下建立对应的配置,且引入mapper的约束。

Config配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--配置环境-->
    <environments default="mysql">
        <!--配置mysql环境-->
        <environment id="mysql">
            <!--配置事务类型-->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置连接池-->
            <dataSource type="POOLED">
                <!--配置连接数据库的基本信息-->
                <property name="driver" value="com.mysql,jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <!--指定映射配置文件-->
    <mappers>
        <mapper resource="com/itheima.dao/IuserDao.xml"/>
    </mappers>
</configuration>

mapper的配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

    <mapper namespace="com.itheima.dao.IUserDao">
    <!--配置查询所有-->
    <select id="findAll">
        select * from USER
    </select>
</mapper>

至此环境搭建基本完成,在进行这些操作前需要将maven项目的环境搭建好,并建立好仓库等。

mybatis的实例

1.在test的java文件夹中以main函数来进行测试,且使用了工厂模式来进行sql语句的执行

public static void main(String[] args) throws Exception{
        //1.读取配置文件
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建SQL Session Factory工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(inputStream);
        //3.使用工厂生产SqlSession对象
        SqlSession session = factory.openSession();
        //4.使用SQL Session创建Dao接口代理对象
        IUserDao userDao = session.getMapper(IUserDao.class);
        //5.使用代理对象执行方法
        List<User> users;
        users = userDao.findAll();
        for (User user : users){
            System.out.println(user);
        }
        //6.释放资源
        session.close();
        inputStream.close();
    }

执行后发现报错并不如愿,理想中的报错应该是返回由于映射的没有返回结果而报错,最终发现是自己的mapper地址写错,以及jdbc的驱动加载写错。

  • mybatis的映射配置文件位置必须和dao接口的包接口相同

  • 映射配置文件mapper的标签namespace属性取值必须是dao接口的全限定类名

  • 映射配置文件的操作配置,id属性取值必须是dao接口的方法名。

实例中使用到的几个类

  1. class Resources
  2. class SqlSessionFactoryBuilder
  3. interface SqlSessionFactory
  4. interface SqlSession

在符合上面的几个条件的情况下,就不需要再写dao的实现类了。

注解方式来使用mybatis

则可以删除每个dao对应的dao.xml改为@select注解,并且指定SQL语句,在config文件中配置mappper时,使用class属性指定dao接口的全限定类名。

自定义MyBatis

  1. 首先需要有数据库的连接信息,通过连接信息,可以创建Connection对象,接下来需要映射的配置信息,最后从映射中配置需要的SQL语句。就可以获取PreparedStatement。通过dom4j来解析这些xml配置。

  2. 根据配置文件的细腻些创建Connection对象,获取预处理对象PrepareSatement接下来执行查询,将遍历的结果集封装,将结果返回。

ArcGIS学习笔记

基本操作

  1. ArcGIS在进行一系列操作后可以保存mxd文件,保存上一次的所有操作与显示方式。

  2. ArcGIS可以将txt与xls(注意:如果为xlsx格式的在10.2中的ArcGIS中无法直接读取,需要转换为xls)格式的数据带入笛卡尔坐标系,需要自己选择地理坐标系,或是投影坐标系(注意投影坐标系与地理坐标系的区别,前者是信息与选择的投影面产生几何变换后的投影,后者是根据不同的坐标,不同的大地水准面制定出的坐标系)

格式化字符

char s[10]
printf(s)

这样虽然也可以输出,但是输入交给用户就会出现问题,如果输入的字符串为”%x%x%x%x”会直接出现内存中的数据,这是由于printf函数不知道参数,对于特定的%,会去取相应的参数,直到检索到字符串结束.所以尽管没有参数,上面的代码也会将字符串后面的内存当作参数,以16进制输出.任意的内存读取需要用到%s,其对应的参量是一个指向字符串首地址的指针,且局部变量(格式化字符串,即在printf中的)是存储在栈中,所以一定可以找到输入的字符串.
此时如果需要修改一些其他变量值,只需要计算参数的偏移量,找出参数位置,通过%n的使用,即可修改程序的参数

kali

kali中在配置burp suite代理时注意将代理改为127.0.0.1后要在浏览器中相应的修改代理至127.0.0.1,同时如果需要访问https的页面需要导入burp suite的CA证书.

练手题目

写在开头

写这篇博客旨在把平日练手的一些有趣的小题分享,很多的题应该都不会涉及复杂的算法只是一些想法比较有意思的小题

1.一串数字,长度未知,求其中只出现一次的数。要求时间复杂度O(1),空间复杂度O(0)

一开始看到这道题想了用标记数组来做,后在看视频的时候无意间看到了”^”这个符号想起来了用位运算来处理每一个数,如果两个数相同异或就会变成0,任何数和0异或又是
其本身,代码如下**

#include<stdio.h>
int main()
{
    int n,ans=0;
    while(EOF!=scanf("%d",&n))
    {
        ans^=n;
    }
    printf("%d\n",ans);
    return 0;
}

2.给出三个队列 s1,s2,s3 ,判断 s3 是否是由 s1 和 s2 交叉得来。 如:s1 为 aabcc , s2 为 dbbca。 当 s3 aadbbcbcac 时,返回 true(即将 s1 拆成三部分: aa,bc,c 分别插入 s2 对应位置) 否则返回 false。**

一开始想到就是字符串匹配问题,代码如下,但没有考虑,前一串以最优情况匹配,后一串在匹配时会因前一串把优先把靠前位置都占据,而出现匹配不
上的情况,因此加以优化,将第一串从后往前匹配,将更优的位置给下一串留下,中途甚至想过用每个字符的ASCII码建一个数组,然后只用匹配数量即可,但后来发现这样匹配没有考虑到字符串本来的顺序问题,放弃。

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<iostream>
using namespace std;
char a[100];
char b[100];
char c[200];
int ans[200];
char d[400];
int main()
{
    memset(ans,0,sizeof(ans));
    int i = 0 ,flag = 1 ,mark = 1 , m = 0 , n = 0 ,pos;
   scanf("%s",d);
   getchar();
   while(d[i]!=',')
   {
       a[i] = d[i];
       i++;
   }
   a[i] = '\0';
   i++;
   while(d[i]!=',')
   {
       b[m++] = d[i++];
   }
   b[m] = '\0';
   i++;
   int len = strlen(d);
   while(i<len)
   {
       c[n++] = d[i++];
   }
   c[n] = '\0';
   int lena = strlen(a);
   pos = lena-1;
   for(int j = n-1 ; j >=0 ; j--)
   {
       if(c[j]==a[pos])
       {
           ans[j] = 1;
           pos--;
       }
   }
   if(pos!=-1)
   {
       flag = 0;
   }
   pos = 0;
   for(int j = 0 ; j < n ; j++)
   {
       if(c[j]==b[pos]&&ans[j]!=1)
       {
           pos++;
       }
   }

   if(pos != m)
   {
       mark = 0;
   }
   if(mark&&flag)
   {
       printf("true\n");
   }
   else{
    printf("false\n");
   }
   return 0;
}

单片机学习笔记

单片机工作基本时序

1.振荡周期即提供时钟脉冲信号的震荡源的周期,常见(11.0592)状态周期为时钟周期的两倍即振荡周期的二分频

2.机器周期 包含6个状态周期 。 12个时钟周期 ,在一个周期内cpu完成一个独立的操作
指令周期 CPU完成一条操作所需的全部时间

3.三极管:流控流,压控压型,PNP型在be之间的节电压正偏时,导通(c极连接了vcc,b极连接单片机,在b极给一个低电压时导通)
~按位取反,今天在实现模拟二进制递增时,使用了在每一位为1时让单片机在对应的位置上亮,但单片机上控制led亮,需要单片机输出一个低电平,刚好使用取反。

单片机学习在最近需要搁置一下了,因为学习单片机主要是为了之后的那个项目,但近期先准备好完成ctf的比赛以及学校派发的任务先.2019-10-23

Arduino学习笔记

1.Arduino会在启动时执行void setup(){ }中的指令,后无限循环void loop(){ }中的指令,pinMode()指定某个端口的动作,有INPUT和OUTPUT.
2.digitalWrite(),在一个pin口被定义为OUPUT后,使用该函数可以将其定义为HIGH或者LOW,如果为INPUT时,如果为HIGH则将启用内部上拉,LOW禁用内部上拉。同时Ardunio自己内置了delay函数。
3.使用Serial()可以与电脑连接。从Serial.begin()开始,后续可以调用serial中的其他函数。(println等等)

变量覆盖

$与$$的使用 $$称为可变变量
例如:
$value){ ${$key} = $value; } echo $a; ?>
提交?a=1,会被解析为$a=1,造成变量覆盖

extract()使用不当
与上一个意思基本相同也是将数组中的每一个键值对赋值为单独的变量;
parse_str()将查询字符串解析到变量中

import_request_variables()将GET,POST,COOKIE的参数注册成变量也会造成变量覆盖