【程序】猫狗分类程序:包括网络结构、数据集处理、训练、测试-程序员宅基地

技术标签: 小菜鸡加油  

网络的输出层设置两个神经元的原因:神经网络有两个输出值对应两种类别,通过学习数据的不同特征,让两种类别在输出上有体现,即0趋近于猫,1趋近于狗。宏观上来看,神经网络具有了辨识猫狗的能力。

训练过程中,有对GT由一维处理成二维的操作,目的也是为了和神经网络二维的输出进行匹配。

程序1中测试程序有误。程序2进行了修改,修改后在12000张图片中正确率达到了90%,浮动在2%以内,二分类的全连接网络效果还是可以的。

程序1:

import torch
import os
import numpy as np
from PIL import Image
from torch.utils.data import Dataset, DataLoader
import torch.nn as nn
import matplotlib.pyplot as plt


class MyDataSet(Dataset):
    def __init__(self, path):
        """根据路径获得数据集"""
        self.path = path

        """读取路径下的所有文件"""
        self.dataset = os.listdir(self.path)

        # 均值和方差的求解过程下面会交代
        self.mean = [0.4878, 0.4545, 0.4168]
        self.std = [0.2623, 0.2555, 0.2577]

    def __len__(self):
        """获取数据集的长度"""
        # print("ooo")
        return len(self.dataset)

    def __getitem__(self, index):
        """根据索引获得数据集"""
        # 获得数据的标签
        name = self.dataset[index]

        # 数据集的文件名为i.j.jpeg, 这个标签的第i个位置如果是0表示猫,1则表示狗,第j个位置是图片的个数
        name_list = name.split(".")
        target = int(name_list[0])

        # 这里需要注意,tensor(target) 和Tensor([target])的区别,否则在one-hot解码的时候会出现错误
        target = torch.tensor(target)

        """数据预处理"""
        # 打开图片
        img = Image.open(os.path.join(self.path, name))

        # 设置图片大小
        # img = np.resize(img, (3, 10, 10))

        # 归一化,先将图片转化为一个矩阵,然后除以255
        img = np.array(img) / 255
        # print("OOK")

        # # 去均值
        img = (img - self.mean) / self.std

        # 换轴 H W C 转换为 C H W ,这里需要注意下,其实我们可以不这么处理,在前面设置图片大小的时候设置为3 * 100 * 100 的就可以。
        train_data = torch.tensor(img, dtype=torch.float32).permute(2, 0, 1)
        return train_data, target
    # def aaa(self):
    #     print("OK")


class MyNetwork(nn.Module):
    def __init__(self):
        super(MyNetwork, self).__init__()

        """
        nn.Sequential:一个有序的容器,神经网络模块将按照在传入构造器的顺序依次被添加到计算图中执行

        """
        self.line1 = nn.Sequential(
            nn.Linear(in_features=3 * 100 * 100, out_features=512),
            nn.ReLU(),
            nn.Linear(in_features=512, out_features=256),
            nn.ReLU(),
            nn.Linear(in_features=256, out_features=128),
            nn.ReLU(),
            nn.Linear(in_features=128, out_features=256),
            nn.ReLU(),
            nn.Linear(in_features=256, out_features=512),
            nn.ReLU(),
            nn.Linear(in_features=512, out_features=256),
            nn.ReLU(),
            nn.Linear(in_features=256, out_features=2),
        )

    def forward(self, parse):
        data = torch.reshape(parse, shape=(-1, 3 * 100 * 100))
        return self.line1(data)


class Train(object):
    def __init__(self, path):
        self.path = path
        self.test_dataset = MyDataSet(os.path.join(self.path))
        self.train_dataset = MyDataSet(os.path.join(self.path))
        self.criterion = torch.nn.MSELoss()
        self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
        self.net = MyNetwork().to(self.device)
        self.optimize = torch.optim.Adam(self.net.parameters())

    def dataLoader(self, batch):
        train_data_loader = DataLoader(dataset=self.train_dataset, batch_size=batch, shuffle=True)
        test_data_loader = DataLoader(dataset=self.test_dataset, batch_size=batch, shuffle=True)
        return train_data_loader, test_data_loader

    def trainNet(self, batch, epoch):
        train_data_loader, test_data_loader = self.dataLoader(batch)
        losses = []
        accuracy = []
        for i in range(epoch):
            for j, (Input, target) in enumerate(train_data_loader):
                Input = Input.to(self.device)
                out_put = self.net(Input)
                # print("out_put:",out_put)
                """
                one - hot 编码:
                torch.scatter(self, dim, index, value)
                该代码表示把value按照index根据dim的方向填入self中
                Example:
                    index = torch.tensor([0, 2, 4, 1])
                    src = torch.zeros(4, 5)
                    print(src.shape)
                    out = torch.scatter(src, dim=1, index=index.view(-1, 1), value=1)
                    print(out)

                """
                # print(target,target.size())
                target = torch.zeros(target.size(0), 2).scatter_(1, target.view(-1, 1), 1).to(self.device)
                # print(target,target.size())
                # input()

                loss = self.criterion(out_put, target)
                a=loss.item()
                losses.append(loss.item())

                """ 梯度清零"""
                self.optimize.zero_grad()
                loss.backward()
                self.optimize.step()
                if j % 5 == 0:
                    print("训练轮次:epoch{}/{},迭代次数:iteration{}/{}".format(i, epoch, j, len(train_data_loader)))
                    # print(out_put,out_put.argmax(1))
                    # print(target,target.argmax(1))
                    # input()
                    acc = torch.mean((out_put.argmax(1) == target.argmax(1)), dtype=torch.float32)
                    accuracy.append(acc.item())
                    print("训练准确率为:accuracy = %s , loss值为:%s" % (acc.item(), loss.item()))
                    plt.clf()
                    plt.ion()
                    """加载loss曲线"""
                    plt.subplot(2, 1, 1)
                    plt.tight_layout(2)
                    plt.plot(losses, label="loss")
                    plt.legend(loc='best')

                    """加载accuracy曲线"""
                    plt.subplot(2, 1, 2)

                    """设置图像之间的距离"""
                    plt.tight_layout(2)
                    plt.plot(accuracy, label="accuracy")
                    """显示图例"""
                    plt.legend(loc='best')
                    plt.pause(0.01)
                    plt.show()
            torch.save(self.net, "model/net.pth")

    # 测试
    def Test(self, batch):
        train_data_loader, test_data_loader = self.dataLoader(batch)
        plt.ion()
        for k, (In, tgt) in enumerate(test_data_loader):
            print(k)
            print(self.device)
            # In = In.to(self.device)
            In=In.cuda()
            """加载测试图片"""
            # 加载训练好的网络
            test_Net = torch.load('model/net.pth')

            # 这是可视化训练图片的第一步,进行反算(Input * 标准差+均值)*255
            # 这里输入In的维度是(batch, 3, 100, 100 ),std 和mean是矩阵,所以给它转换维度才能与输入做运算
            img = (In.cpu().data.numpy() * np.array(self.train_dataset.std).reshape(1, 3, 1, 1) + np.array(
                self.train_dataset.mean).reshape(1, 3, 1, 1)) * 255
            img = np.resize(img, (100, 100))

            """显示测试结果"""
            if 0 < k <= batch:
                plt.subplot(3, 3, k)
                plt.tight_layout(1)
                plt.imshow(img)
                predict = test_Net(In)
                print("predict", torch.argmax((predict[k-1])).item())
                predict_result = "cat" if torch.argmax(predict[k - 1]).item() == 0 else "dog"
                print(predict_result)
                plt.title(predict_result)
                plt.axis('off')
                plt.pause(1)
                plt.show()
                plt.savefig("result.jpg")
            elif k == 0:
                continue
            else:
                print("图片测试完毕,请查看!")
                break


if __name__ == '__main__':
    path = r"./cat_dog/img"
    # 训练
    t = Train(path)
    t.trainNet(50, 10)

    # 测试
    t.Test(batch=11)

对测试部分程序进行修改。

程序2:

import torch
import os
import numpy as np
from PIL import Image
from torch.utils.data import Dataset, DataLoader
import torch.nn as nn
import matplotlib.pyplot as plt


class MyDataSet(Dataset):
    def __init__(self, path):
        """根据路径获得数据集"""
        self.path = path

        """读取路径下的所有文件"""
        self.dataset = os.listdir(self.path)

        # 均值和方差的求解过程下面会交代
        self.mean = [0.4878, 0.4545, 0.4168]
        self.std = [0.2623, 0.2555, 0.2577]

    def __len__(self):
        """获取数据集的长度"""
        # print("ooo")
        return len(self.dataset)

    def __getitem__(self, index):
        """根据索引获得数据集"""
        # 获得数据的标签
        name = self.dataset[index]

        # 数据集的文件名为i.j.jpeg, 这个标签的第i个位置如果是0表示猫,1则表示狗,第j个位置是图片的个数
        name_list = name.split(".")
        target = int(name_list[0])

        # 这里需要注意,tensor(target) 和Tensor([target])的区别,否则在one-hot解码的时候会出现错误
        target = torch.tensor(target)

        """数据预处理"""
        # 打开图片
        img = Image.open(os.path.join(self.path, name))

        # 设置图片大小
        # img = np.resize(img, (3, 10, 10))

        # 归一化,先将图片转化为一个矩阵,然后除以255
        img = np.array(img) / 255
        # print("OOK")

        # # 去均值
        img = (img - self.mean) / self.std

        # 换轴 H W C 转换为 C H W ,这里需要注意下,其实我们可以不这么处理,在前面设置图片大小的时候设置为3 * 100 * 100 的就可以。
        train_data = torch.tensor(img, dtype=torch.float32).permute(2, 0, 1)
        return train_data, target
    # def aaa(self):
    #     print("OK")


class MyNetwork(nn.Module):
    def __init__(self):
        super(MyNetwork, self).__init__()

        """
        nn.Sequential:一个有序的容器,神经网络模块将按照在传入构造器的顺序依次被添加到计算图中执行

        """
        self.line1 = nn.Sequential(
            nn.Linear(in_features=3 * 100 * 100, out_features=512),
            nn.ReLU(),
            nn.Linear(in_features=512, out_features=256),
            nn.ReLU(),
            nn.Linear(in_features=256, out_features=128),
            nn.ReLU(),
            nn.Linear(in_features=128, out_features=256),
            nn.ReLU(),
            nn.Linear(in_features=256, out_features=512),
            nn.ReLU(),
            nn.Linear(in_features=512, out_features=256),
            nn.ReLU(),
            nn.Linear(in_features=256, out_features=2),
        )

    def forward(self, parse):
        data = torch.reshape(parse, shape=(-1, 3 * 100 * 100))
        return self.line1(data)


class Train(object):
    def __init__(self, path):
        self.path = path
        self.test_dataset = MyDataSet(os.path.join(self.path))
        self.train_dataset = MyDataSet(os.path.join(self.path))
        self.criterion = torch.nn.MSELoss()
        self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
        self.net = MyNetwork().to(self.device)
        self.optimize = torch.optim.Adam(self.net.parameters())

    def dataLoader(self, batch):
        train_data_loader = DataLoader(dataset=self.train_dataset, batch_size=batch, shuffle=True)
        test_data_loader = DataLoader(dataset=self.test_dataset, batch_size=batch, shuffle=True)
        return train_data_loader, test_data_loader

    def trainNet(self, batch, epoch):
        train_data_loader, test_data_loader = self.dataLoader(batch)
        losses = []
        accuracy = []
        for i in range(epoch):
            for j, (Input, target) in enumerate(train_data_loader):
                Input = Input.to(self.device)
                out_put = self.net(Input)
                # print("out_put:",out_put)
                """
                one - hot 编码:
                torch.scatter(self, dim, index, value)
                该代码表示把value按照index根据dim的方向填入self中
                Example:
                    index = torch.tensor([0, 2, 4, 1])
                    src = torch.zeros(4, 5)
                    print(src.shape)
                    out = torch.scatter(src, dim=1, index=index.view(-1, 1), value=1)
                    print(out)

                """
                # print(target,target.size())
                target = torch.zeros(target.size(0), 2).scatter_(1, target.view(-1, 1), 1).to(self.device)
                # print(target,target.size())
                # input()

                loss = self.criterion(out_put, target)
                a = loss.item()
                losses.append(loss.item())

                """ 梯度清零"""
                self.optimize.zero_grad()
                loss.backward()
                self.optimize.step()
                if j % 5 == 0:
                    print("训练轮次:epoch{}/{},迭代次数:iteration{}/{}".format(i, epoch, j, len(train_data_loader)))
                    # print(out_put,out_put.argmax(1))
                    # print(target,target.argmax(1))
                    # input()
                    acc = torch.mean((out_put.argmax(1) == target.argmax(1)), dtype=torch.float32)
                    accuracy.append(acc.item())
                    print("训练准确率为:accuracy = %s , loss值为:%s" % (acc.item(), loss.item()))
                    plt.clf()
                    plt.ion()
                    """加载loss曲线"""
                    plt.subplot(2, 1, 1)
                    plt.tight_layout(2)
                    plt.plot(losses, label="loss")
                    plt.legend(loc='best')

                    """加载accuracy曲线"""
                    plt.subplot(2, 1, 2)

                    """设置图像之间的距离"""
                    plt.tight_layout(2)
                    plt.plot(accuracy, label="accuracy")
                    """显示图例"""
                    plt.legend(loc='best')
                    plt.pause(0.01)
                    plt.show()
            torch.save(self.net, "model/net.pth")

    # 测试
    def Test(self, batch):
        train_data_loader, test_data_loader = self.dataLoader(batch)
        plt.ion()
        i = 0
        for k, (In, tgt) in enumerate(test_data_loader):
            print(k)
            print(self.device)
            # In = In.to(self.device)
            In = In.cuda()
            # print(In.size())
            # input()
            """加载测试图片"""
            # 加载训练好的网络
            test_Net = torch.load('model/net.pth')

            # 这是可视化训练图片的第一步,进行反算(Input * 标准差+均值)*255
            # 这里输入In的维度是(batch, 3, 100, 100 ),std 和mean是矩阵,所以给它转换维度才能与输入做运算
            img = (In.cpu().data.numpy() * np.array(self.train_dataset.std).reshape(1, 3, 1, 1) + np.array(
                self.train_dataset.mean).reshape(1, 3, 1, 1)) * 255
            img = np.resize(img, (100, 100))

            predict = test_Net(In)
            # predict_result = "cat" if predict[k - 1].argmax(1).item() == 0 else "dog"
            print(tgt)
            # TP = np.intersect1d(tgt.cpu().numpy(),tgt.cpu().numpy())
            print(predict.argmax(1).cpu())

            print(predict)
            print(predict.argmax(1).cpu() == tgt.cpu())
            for x in predict.argmax(1).cpu() == tgt.cpu():
                if x == True:
                    i += 1
            print(i)

            # input()
            # print(len(tgt.cpu() == predict.argmax(1).cpu()))
            # print(len(TP))
            # print(TP / len(tgt))
            # input()

        print("{:%}".format(i/12000))
        
            #
            # """显示测试结果"""
            # if 0 < k <= batch:
            #     plt.subplot(3, 3, k)
            #     plt.tight_layout(1)
            #     plt.imshow(img)
            #     predict = test_Net(In)
            #     print(predict.size(),predict)
            #     input()
            #     # print("predict", torch.argmax((predict[k-1])).item())
            #     predict_result = "cat" if predict[k - 1].argmax(1).item() == 0 else "dog"
            #
            #     print(predict_result)
            #     plt.title(predict_result)
            #     plt.axis('off')
            #     plt.pause(1)
            #     plt.show()
            #     plt.savefig("result.jpg")
            # elif k == 0:
            #     continue
            # else:
            #     print("图片测试完毕,请查看!")
            #     break


if __name__ == '__main__':
    path = r"./cat_dog/img"
    # 训练
    t = Train(path)
    t.trainNet(200, 10)

    # 测试
    t.Test(batch=200)

注释去掉后:

import torch
import os
import numpy as np
from PIL import Image
from torch.utils.data import Dataset, DataLoader
import torch.nn as nn
import matplotlib.pyplot as plt


class MyDataSet(Dataset):
    def __init__(self, path):
        """根据路径获得数据集"""
        self.path = path

        """读取路径下的所有文件"""
        self.dataset = os.listdir(self.path)

        # 均值和方差的求解过程下面会交代
        self.mean = [0.4878, 0.4545, 0.4168]
        self.std = [0.2623, 0.2555, 0.2577]

    def __len__(self):
        """获取数据集的长度"""
        # print("ooo")
        return len(self.dataset)

    def __getitem__(self, index):
        """根据索引获得数据集"""
        # 获得数据的标签
        name = self.dataset[index]

        # 数据集的文件名为i.j.jpeg, 这个标签的第i个位置如果是0表示猫,1则表示狗,第j个位置是图片的个数
        name_list = name.split(".")
        target = int(name_list[0])

        # 这里需要注意,tensor(target) 和Tensor([target])的区别,否则在one-hot解码的时候会出现错误
        target = torch.tensor(target)

        """数据预处理"""
        # 打开图片
        img = Image.open(os.path.join(self.path, name))

        # 设置图片大小
        # img = np.resize(img, (3, 10, 10))

        # 归一化,先将图片转化为一个矩阵,然后除以255
        img = np.array(img) / 255
        # print("OOK")

        # # 去均值
        img = (img - self.mean) / self.std

        # 换轴 H W C 转换为 C H W ,这里需要注意下,其实我们可以不这么处理,在前面设置图片大小的时候设置为3 * 100 * 100 的就可以。
        train_data = torch.tensor(img, dtype=torch.float32).permute(2, 0, 1)
        return train_data, target
    # def aaa(self):
    #     print("OK")


class MyNetwork(nn.Module):
    def __init__(self):
        super(MyNetwork, self).__init__()

        """
        nn.Sequential:一个有序的容器,神经网络模块将按照在传入构造器的顺序依次被添加到计算图中执行

        """
        self.line1 = nn.Sequential(
            nn.Linear(in_features=3 * 100 * 100, out_features=512),
            nn.ReLU(),
            nn.Linear(in_features=512, out_features=256),
            nn.ReLU(),
            nn.Linear(in_features=256, out_features=128),
            nn.ReLU(),
            nn.Linear(in_features=128, out_features=256),
            nn.ReLU(),
            nn.Linear(in_features=256, out_features=512),
            nn.ReLU(),
            nn.Linear(in_features=512, out_features=256),
            nn.ReLU(),
            nn.Linear(in_features=256, out_features=2),
        )

    def forward(self, parse):
        data = torch.reshape(parse, shape=(-1, 3 * 100 * 100))
        return self.line1(data)


class Train(object):
    def __init__(self, path):
        self.path = path
        self.test_dataset = MyDataSet(os.path.join(self.path))
        self.train_dataset = MyDataSet(os.path.join(self.path))
        self.criterion = torch.nn.MSELoss()
        self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
        self.net = MyNetwork().to(self.device)
        self.optimize = torch.optim.Adam(self.net.parameters())

    def dataLoader(self, batch):
        train_data_loader = DataLoader(dataset=self.train_dataset, batch_size=batch, shuffle=True)
        test_data_loader = DataLoader(dataset=self.test_dataset, batch_size=batch, shuffle=True)
        return train_data_loader, test_data_loader

    def trainNet(self, batch, epoch):
        train_data_loader, test_data_loader = self.dataLoader(batch)
        losses = []
        accuracy = []
        for i in range(epoch):
            for j, (Input, target) in enumerate(train_data_loader):
                Input = Input.to(self.device)
                out_put = self.net(Input)
                # print("out_put:",out_put)
                """
                one - hot 编码:
                torch.scatter(self, dim, index, value)
                该代码表示把value按照index根据dim的方向填入self中
                Example:
                    index = torch.tensor([0, 2, 4, 1])
                    src = torch.zeros(4, 5)
                    print(src.shape)
                    out = torch.scatter(src, dim=1, index=index.view(-1, 1), value=1)
                    print(out)

                """
                # print(target,target.size())
                target = torch.zeros(target.size(0), 2).scatter_(1, target.view(-1, 1), 1).to(self.device)
                # print(target,target.size())
                # input()

                loss = self.criterion(out_put, target)
                a = loss.item()
                losses.append(loss.item())

                """ 梯度清零"""
                self.optimize.zero_grad()
                loss.backward()
                self.optimize.step()
                if j % 5 == 0:
                    print("训练轮次:epoch{}/{},迭代次数:iteration{}/{}".format(i, epoch, j, len(train_data_loader)))
                    # print(out_put,out_put.argmax(1))
                    # print(target,target.argmax(1))
                    # input()
                    acc = torch.mean((out_put.argmax(1) == target.argmax(1)), dtype=torch.float32)
                    accuracy.append(acc.item())
                    print("训练准确率为:accuracy = %s , loss值为:%s" % (acc.item(), loss.item()))
                    plt.clf()
                    plt.ion()
                    """加载loss曲线"""
                    plt.subplot(2, 1, 1)
                    plt.tight_layout(2)
                    plt.plot(losses, label="loss")
                    plt.legend(loc='best')

                    """加载accuracy曲线"""
                    plt.subplot(2, 1, 2)

                    """设置图像之间的距离"""
                    plt.tight_layout(2)
                    plt.plot(accuracy, label="accuracy")
                    """显示图例"""
                    plt.legend(loc='best')
                    plt.pause(0.01)
                    plt.show()
            torch.save(self.net, "model/net.pth")

    # 测试
    def Test(self, batch):
        train_data_loader, test_data_loader = self.dataLoader(batch)
        plt.ion()
        i = 0
        for k, (In, tgt) in enumerate(test_data_loader):
            print(k)
            print(self.device)
            # In = In.to(self.device)
            In = In.cuda()
            # print(In.size())
            # input()
            """加载测试图片"""
            # 加载训练好的网络
            test_Net = torch.load('model/net.pth')

            # 这是可视化训练图片的第一步,进行反算(Input * 标准差+均值)*255
            # 这里输入In的维度是(batch, 3, 100, 100 ),std 和mean是矩阵,所以给它转换维度才能与输入做运算
            img = (In.cpu().data.numpy() * np.array(self.train_dataset.std).reshape(1, 3, 1, 1) + np.array(
                self.train_dataset.mean).reshape(1, 3, 1, 1)) * 255
            img = np.resize(img, (100, 100))

            predict = test_Net(In)
            # predict_result = "cat" if predict[k - 1].argmax(1).item() == 0 else "dog"
            print(tgt)
            # TP = np.intersect1d(tgt.cpu().numpy(),tgt.cpu().numpy())
            print(predict.argmax(1).cpu())

            print(predict)
            print(predict.argmax(1).cpu() == tgt.cpu())
            for x in predict.argmax(1).cpu() == tgt.cpu():
                if x == True:
                    i += 1
            print(i)

        print("{:%}".format(i/12000))




if __name__ == '__main__':
    path = r"./cat_dog/img"
    # 训练
    t = Train(path)
    t.trainNet(200, 10)

    # 测试
    t.Test(batch=200)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/nyist_yangguang/article/details/118466508

智能推荐

c# 调用c++ lib静态库_c#调用lib-程序员宅基地

文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib

deepin/ubuntu安装苹方字体-程序员宅基地

文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang

html表单常见操作汇总_html表单的处理程序有那些-程序员宅基地

文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些

PHP设置谷歌验证器(Google Authenticator)实现操作二步验证_php otp 验证器-程序员宅基地

文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器

【Python】matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距-程序员宅基地

文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距

docker — 容器存储_docker 保存容器-程序员宅基地

文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器

随便推点

网络拓扑结构_网络拓扑csdn-程序员宅基地

文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn

JS重写Date函数,兼容IOS系统_date.prototype 将所有 ios-程序员宅基地

文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios

如何将EXCEL表导入plsql数据库中-程序员宅基地

文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql

Git常用命令速查手册-程序员宅基地

文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...

分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120-程序员宅基地

文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120

【C++缺省函数】 空类默认产生的6个类成员函数_空类默认产生哪些类成员函数-程序员宅基地

文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数

推荐文章

热门文章

相关标签