首页 文章 精选 留言 我的

精选列表

搜索[快速入门],共10000篇文章
优秀的个人博客,低调大师

入门学者提供简单介绍Linux ldd命令

如果您的工作涉及到 Linux 中的可执行文件和共享库的知识,则需要了解几种命令行工具。其中之一是 ldd ,您可以使用它来访问共享对象依赖关系。在本教程中,我们将使用一些易于理解的示例来讨论此实用程序的基础知识。 请注意,这里提到的所有示例都已在 Ubuntu 16.04 LTS 上进行了测试。 Linux ldd 命令 正如开头已经提到的,ldd 命令打印共享对象依赖关系。以下是该命令的语法: ldd [option]... file... 下面是该工具的手册页对它作出的解释: ldd 会输出命令行指定的每个程序或共享对象所需的共享对象(共享库)。 以下使用问答的方式让您更好地了解ldd的工作原理。 问题一、 如何使用 ldd 命令? ldd 的基本用法非常简单,只需运行 ldd 命令以及可执行文件或共享对象的文件名称作为输入。 ldd [object-name] 例如: ldd test How to use ldd 所以你可以看到所有的共享库依赖已经在输出中产生了。 Q2、 如何使 ldd 在输出中生成详细的信息? 如果您想要 ldd 生成详细信息,包括符号版本控制数据,则可以使用 -v 命令行选项。例如,该命令 ldd -v test 当使用 -v 命令行选项时,在输出中产生以下内容: How to make ldd produce detailed information in output Q3、 如何使 ldd 产生未使用的直接依赖关系? 对于这个信息,使用 -u 命令行选项。这是一个例子: ldd -u test How to make ldd produce unused direct dependencies Q4、 如何让 ldd 执行重定位? 您可以在这里使用几个命令行选项:-d 和 -r。 前者告诉 ldd 执行数据重定位,后者则使 ldd 为数据对象和函数执行重定位。在这两种情况下,该工具都会报告丢失的 ELF 对象(如果有的话)。 ldd -d ldd -r Q5、 如何获得关于ldd的帮助? --help 命令行选项使 ldd 为该工具生成有用的用法相关信息。 ldd --help How get help on ldd 总结 ldd 不像 cd、rm 和 mkdir 这样的工具类别。这是因为它是为特定目的而构建的。该实用程序提供了有限的命令行选项,我们在这里介绍了其中的大部分。要了解更多信息,请前往 ldd的手册页。

优秀的个人博客,低调大师

Python入门(五)字符串各种问题总结

1.字符串中使用引号 非成对出现的引号,用转义字符"\": >>> str1='Where\'re you now?' >>> print(str1) Where're you now? 成对出现的引号:1)单引号中可用双引号 >>> str2='"DJY"' >>> print(str2) "DJY" 2)双引号中可用单引号 >>> str3="'DJY'" >>> print(str3) 'DJY' 3)三引号可保持字符串原来的格式(从转义字符中被解救的感觉) >>> str4='''DJY FXW''' >>> print(str4) DJY FXW >>> str5="""DJY FXW""" >>> print(str5) DJY FXW 如果想在字符串中既有成对单引号又有成对双引号: >>> str61="'djy'" >>> str62='"fxw"' >>> print(str61+str62) 'djy'"fxw" 2.字符串中显示转义字符 如果想在字符串中显示少量转义字符"\": >>> str1='DJY\\FXW' >>> print(str1) DJY\FXW 此种方法常用在:发出系统响铃声 \a,退格符 \b,换行符 \n,横向制表符(TAB) \t,纵向制表符 \v,回车符 \r,换页符 \f,八进制数代表的字符 \o,十六进制数代表的字符 \x,其它的字符以普通格式输出 \other空字符 \0,反斜杠 \。 如果想在字符串中显示大量转义字符"\": >>> str2=r'C:\DJY\djy\d\j\y' #r是来自于原始字符串(raw strings) >>> print(str2) C:\DJY\djy\d\j\y 若还想以结尾,只需改为: >>> str2=r'C:\DJY\djy\d\j\y\\' >>> print(str2) C:\DJY\djy\d\j\y\ 3.字符串运算符 字符索引[] >>> str1='python2048' >>> str1[6] ‘2’ >>> str1[-1] '8' 字符串分片[:] >>> str1='python2048' >>> str1[6:10] '2048' >>> str1[:6] 'python' 字符串连接+ >>> str1='python' >>> str2='2048' >>> str1+str2 'python2048' 字符串重复* >>> str1='python2048' >>> str1*3 'python2048python2048python2048' 4.字符串格式化 字符串格式化符号 格式化字符及其ASCII码:%c >>> '%c %c %c'%(97,98,99) 'a b c' 格式化字符串:%s >>> '%s'%'djy' 'djy' 格式化整数:%d >>> '%d+%d=%d'%(1,2,1+2) '1+2=3' 格式化无符号八进制、十六进制数(小写、大写):%o、%x、%X >>> '%X'%(10) 'A' 格式化定点数,可设置小数点后的精度:%f >>> '%f'%99.09584 '99.095840' 用科学计数法格式化定点数(小写、大写):%e、%E >>> '%e'%99.09584 '9.909584e+01' 根据值的大小决定使用%f还是%e(%E):%g、%G >>> '%G'%99.09584 '99.0958' 格式化操作符辅助指令 显示最小总宽度m,小数点后的位数n:m.n >>> '%9.2f'%99.09584 ' 99.10' 左对齐:- >>> '%-20f'%2 '2.000000 ' 在正数前面显示加号(+):+ >>> '%+f'%2 '+2.000000' 在八进制数前面显示零('0'),在十六进制数前面显示'0x'或'0X' >>> '%#o'%10 '0o12' 显示的数字前面填充'0'取代空格:0 >>> '%020f'%10 '0000000000010.000000' 5.字符串的BIF 把字符串的第一个字符改成大写:capitalize() >>> str1='python精英群' >>> str1.capitalize() 'Python精英群' 把整个字符串的所有字符改为小写:casefold() >>> str2='PYTHON2048' >>> str2.casefold() 'python2048' 将字符串居中,并用空格填充至长度width形成新字符串:center(width) >>> str3='python2048' >>> str3.center(20) ' python2048 ' 返回sub在字符串里出现的次数,start和end参数表示范围:count(sub[,start[,end]]) >>> str4='djydjydjy' >>> str4.count('jy',2,9) 2 检查字符串是否以sub子字符串结束,如果是返回True,否则返回False:endswith(sub[,start[,end]]) >>> str5='djydjydjy' >>> str5.endswith('jy',2,9) True 把字符串中的tab符号(t)转换为空格,如不指定参数,默认空格数tabsize=8:expandtabs([tabsize=8]) >>> str6='djy\tpython\tfxw' >>> str6.expandtabs() 'djy python fxw' 检测sub是否包含在字符串中,如果有则返回索引值,否则返回-1:find(sub[,start[,end]]) >>> str7='djyfxw' >>> str7.find('c') -1 检测sub是否包含在字符串中,如果有则返回索引值,否则会出现Error:index(sub[,start[,end]]) >>> str8='djyfxw' >>> str8.index('c') #发生Error ValueError: substring not found 如果字符串中所有字符都为字母或数字,则返回True,否则返回False:isalnum() >>> str9='djy&fxw' >>> str9.isalnum() False 如果字符串中字符都为字母,则返回True,否则返回False:isalpha() >>> str10='djy&fxw' >>> str10.isalpha() False 如果字符串为Unicode数字、全角数字(双字节)则返回True,罗马数字、汉字数字返回Flase, byte数字(单字节)会出现Error:isdecimal() >>> str11='2048' >>> str11.isdecimal() True 如果字符串为Unicode数字、byte数字(单字节)、全角数字(双字节)、罗马数字则返回True, 汉字数字返回Flase:isdigit() >>> str12='2048' >>> str12.isdigit() True 如果字符串为Unicode数字、全角数字(双字节)、罗马数字、汉字数字则返回True,byte数字(单字节)会出现Error:isnumeric() >>> str13='2048' >>> str13.isnumeric() True 如果字符串中字符都是小写,则返回True,否则返回Flase:islower() >>> str14='奥特曼超人' >>> str14.islower() False 如果字符串中字符都是大写,则返回True,否则返回Flase:isupper() >>> str15='奥特曼超人' >>> str15.isupper() False 如果字符串只包含空格,则返回True,否则返回Flase:isspace() >>> str16=' ' >>> str16.isspace() True 如果字符串是标题化(所有单词都是以大写开始,其余字母均小写),则返回True,否则返回Flase:istitle() >>> str17='Hello,Djy' >>> str17.istitle() True 以字符串为分隔符,插入到sub中所有的字符之间:join(sub) >>> str18='DJY' >>> str18.join('fxw') 'fDJYxDJYw' 返回一个左对齐的字符串,并用空格填充至长度为width的新字符串:ljust(width) >>> str19='DJY' >>> str19.ljust(20) 'DJY ' 将字符串中所有的大写字母转化为小写:lower() >>> str20='DJY' >>> str20.lower() 'djy' 去掉字符串左边的所有空格:lstrip() >>> str21=' DJY' >>> str21.lstrip() 'DJY' 找到子字符串sub,把字符串分成一个三元组(pre_sub,sub,fol_sub),如果字符串中不包含sub则返回('原字符串',","):partition(sub) >>> str22='djyandfxw' >>> str22.partition('and') ('djy', 'and', 'fxw') 把字符串中的old子字符串替换成new子字符串,如果指定count 则替换不能超过count次:replace(old,new[,count]) >>> str23='djyandfxw' >>> str23.replace('a','d',1) 'djydndfxw' 从右开始检测sub是否包含在字符串中,如果有则返回索引值,否则返回-1(与find()类似):rfind(sub[,start[,end]]) 从右开始检测sub是否包含在字符串中,如果有则返回索引值,否则会出现Error(与index()类似):rindex(sub[,start[,end]]) 返回一个右对齐的字符串,并用空格填充长度至width的新字符串:rjust(width) >>> str24='djyandfxw' >>> str24.rjust(20) ' djyandfxw' 从右开始找子字符串sub,把字符串分成一个三元组(pre_sub,sub,fol_sub),如果字符串中不包含sub则返回('原字符串',",")(与partition(sub)类似):rpartition(sub) 删除字符串末尾的所有空格:rstrip() >>> str25='djyandfxw ' >>> str25.rstrip() 'djyandfxw' 不带参数默认是以空格为分隔符切片为字符串,如果有设置maxsplit参数,则仅分割maxsplit个子字符串,返回切片后的子字符串拼接的列表:split(sep=None,maxsplit=-1) >>> str26='djy python 2048 fxw' >>> str26.split() ['djy', 'python', '2048', 'fxw'] 按'n'分隔,返回一个包含各行作为元素的列表,如果指定keepends参数,则返回前keepends行:splitlines(([keepends])) >>> str27='djy\npython\n2048\nfxw' >>> str27.splitlines(2) ['djy\n', 'python\n', '2048\n', 'fxw'] 检查字符串是否以prefix开头,是则返回True,否则返回False:startswith(prefix[,start[,end]]) >>> str28='djywanan' >>> str28.startswith('d') True 删除字符串前边和后边所有的空格,chars参数可以设置删除的字符:strip([chars]) >>> str29='djy wanan' >>> str29.strip('d') 'jy wanan' 翻转字符串中的大小写:swapcase() >>> str30='DJYwanan' >>> str30.swapcase() 'djyWANAN' 返回标题化(所有的单词都是以大写开始,其余字母均为小写)的字符串:title() >>> str31='DJY wanan' >>> str31.title() 'Djy Wanan' 根据table的规则(可以由str.maketrans('a','b')定制)转换字符串中的字符:translate(table) >>> str32='DJYDJYDJY' >>> str32.translate(str.maketrans('DJY','FXW')) 'FXWFXWFXW' 将字符串中所有的小写转化为大写:upper() >>> str33='djywanan' >>> str33.upper() 'DJYWANAN' 返回长度为width的字符串,原字符串右对齐,前面用0填充:zfill(width) >>> str34='djywanan' >>> str34.zfill(20) '000000000000djywanan' 将字符串格式化:format()1)使用位置参数: >>> 'I like {1},{0},in particular {2}.--{2}'.format('music','dance','DJY') 'I like dance,music,in particular DJY.--DJY' >>> list1=['music','dance','DJY'] >>> 'I like {},{},in particular {}'.format(*list1) 'I like music,dance,in particular DJY' 位置参数不受顺序约束,只要format里有对应的参数值即可为{},参数索引从0开,传入位置参数列表可用*列表。2)使用关键字参数: >>> hash1={'music':'psychedelic rock','dance':'Latin','name':'DJY'} >>> 'I like {music},{dance},in particular {name}'.format(**hash1) 'I like psychedelic rock,Latin,in particular DJY' >>> hash1={'music':'psychedelic rock','dance':'Latin','name':'DJY'} >>> 'I like {music},{dance},in particular {name}'.format(music='classical music',dance='tango',name='FXW') 'I like classical music,tango,in particular FXW' 关键字参数必须要一一对应,以**字典格式用字典输入关键字参数。3)如果想输出{} >>> '{{0}}'.format('djy') '{0}' 4)精度与进制转换: >>> '{0:.2f}{1}'.format(1/2,'km') '0.50km' >>> '{0:x}'.format(10) #转换成十六进制 'a' >>> '{:,}'.format(123456789) #千分位格式化 '123,456,789' 5)填充与格式化:{填充字符} >>> '{0:*>10}'.format(20) #<左对齐,>右对齐,=居中 '********20' 以encoding指定的编码格式对字符串进行编码,以decoding指定的解码码格式对字符串进行解码:encode(encoding='utf-8',errors='strict')、decode(encoding='utf-8',errors='strict') Python3中,以str型代替了unicode类型,经过编码后变为了字节类型(bytes),而但是两个函数的使用方法不变: >>> a='djy' >>> a_utf8=a.encode("UTF-8") #以UTF-8编码对a进行编码,获得bytes类型对象 >>> a_utf8.decode("UTF-8",'strict') #对a_utf8进行解码得到的结果,将无法还原原来的字符串内容 'djy' END!

优秀的个人博客,低调大师

java入门(p2)进入java的世界

浅谈java世界(连载中P2) 前回说完java的基本特点之后,做一个补充,java的语言特性,这个记住就行了,write-once+run-anywhere(理解就好,大概就是写一次哪儿都能用) 这回讲java的程序结构 这个时候要理解一些词汇:1.source file(源文件) 2.class(类) 3.method(方法) 4,statement(语句) 看不懂记不住没有概念?慌什么,直接上图!直观点儿。 源文件是什么? 源文件拓展名为.java很好记,它里面至少包含一个类。 什么是类? 类中带有一个或者多个方法。比如人类有什么样的方法?说话的方法,跑步的方法,这些方法都是基于在人的身体上的。所以方法的使用必须在类中先定义了,也就是告诉编译器我是一个人。虽然很蠢,但是这是必要的。不照做当然是bug伺候。 什么是方法? 接着上面的说,方法是待在类里面的,要去执行一些特定的指令的,比如吃饭的方法,喝水的方法,针对于人类而言的。它是由一堆语句组成的,你可以把它想象成一个过程,(吃饭的方法:先拿筷子,然后夹菜,放进嘴里,咀嚼,…..自己想吧,就是这个样子的) 什么是语句? (吃饭的方法:先拿筷子,然后夹菜,放进嘴里,咀嚼,…..)开括号里都是语句。 *- - - 上面的文字也写一个例子吧。专业点,顺便翻译一下!- - 这就是程序最终的样子吗?这样就是一个能运行的程序了吗?大概意思对了,但是还不可以运行哒,P1中说到代码是要给虚拟机看的,如果有一百个人,也就意味着有100个人都有吃饭的方法,虚拟机从哪儿入手,别说机器了就是我本人也很慌,机器笨笨的,总得有一个标志来开始吧,这个时候充当开头的主方法显得尤为666,当java虚拟机启动执行的时候,它会寻找你写的命令行里面的指定从哪儿开头的类,然后去寻找一个特定的方法,也就是常说常说常说的主方法。Like this~: public static void main(String [] args ){ //代码在这儿写上} 虚拟机就会从这儿开始一条一条的读下去你的指令。好了好了我们来写一段真正能去运行的代码吧。 public class Human{ public static void main (String [] args){System.out.print(“hello world.妈呀这个句子都要听途啦,不过还是很有代表性的,嘻嘻”);}} 先照着敲一下,看看有点击运行有什么效果,不会运行就太笨啦~自己想办法!慢慢解释一下:所有开头的public都是公开给其他类的存取权限;class是类的声明,说明这是一个类,比如class pig{}一个猪类class car{}一个车类;太好理解了;void是表示没有返回值;(String[]args)表示要传String的数组给这个方法当参数,先不用管这个;System.out.print(print中文是打印的意思)这是java的标准输出,整个句子意思是 打印括号里面的内容

优秀的个人博客,低调大师

JSON入门看这一篇就够了

什么是JSON JSON:JavaScript Object Notation 【JavaScript 对象表示法】 JSON 是存储和交换文本信息的语法。类似 XML。 JSON采用完全独立于任何程序语言的文本格式,使JSON成为理想的数据交换语言S 为什么需要JSON 提到JSON,我们就应该和XML来进行对比。XML也是一种存储和交换文本信息的手段。那么JSON好在哪里呢?? JSON 比 XML 更小、更快,更易解析。 javaScript原生支持JSON,解析速度会很快 XML解析成DOM对象的时候,浏览器【IE和fireFox】会有差异 使用JSON会更简单 更加容易创建JavaScript对象 var p = {'city':['北京','上海','广州','深圳']}; for(var i=0;i<p.city.length;i++){ document.write(p.city[i]+"<br/>"); } JSON语法 客户端与服务端的交互数据无非就是两种 数组 对象 于是乎,JSON所表示的数据要么就是对象,要么就是数组 JSON语法是javaScript语法的子集,javaScript用[]中括号来表示数组,用{}大括号来表示对象,JSON亦是如此 JSON数组: var employees = [ { "firstName":"Bill" , "lastName":"Gates" }, { "firstName":"George" , "lastName":"Bush" }, { "firstName":"Thomas" , "lastName": "Carter" } ]; JSON对象 var obj = { age: 20, str: "zhongfucheng", method: function () { alert("我爱学习"); } }; 当然啦,数组可以包含对象,在对象中也可以包含数组 解析JSON javaScript原生支持JSON的,我们可以使用eval()函数来解析JSON,把JSON文本数据转换成一个JavaScript对象。 function test() { //在写JOSN的时候,记得把带上逗号 var txt = "{a:123," + "b:'zhongfucheng'}"; //使用eval解析JSON字符串,需要增添() var aa = eval("(" + txt + ")"); alert(aa); } 效果 不用框架时将JavaBean转成JSON 使用Strus2的时候,Struts2自带了组件能够让JavaBean对象、集合转成是JSON,不用我们自己拼接...这是非常方便的。 使用SpringMVC的时候,SpringMVC也支持将JavaBean转成JSON 但是,我们不一定使用框架来做开发呀。因此,我们还得学习使用第三方库来将JavaBean对象、集合转成JSON 导入开发包 commons-io-2.0.1.jar commons-lang-2.5.jar commons-collections-3.1.jar commons-beanutils-1.7.0.jar ezmorph-1.0.3.jar json-lib-2.1-jdk15.jar 事例代码 package cn.itcast.javaee.js.bean2json; import net.sf.json.JSONArray; import java.util.*; /** * 使用第三方工具,将JavaBean对象/List或Set或Map对象转成JSON * @author AdminTC */ public class TestBean2Json { private static void javabean2json() { City city = new City(1,"广州"); JSONArray jSONArray = JSONArray.fromObject(city); String jsonJAVA = jSONArray.toString(); System.out.println(jsonJAVA); //[{"id":1,"name":"广州"}] } private static void list2json() { List<City> cityList = new ArrayList<City>(); cityList.add(new City(1,"广州")); cityList.add(new City(2,"珠海")); JSONArray jSONArray = JSONArray.fromObject(cityList); String jsonJAVA = jSONArray.toString(); System.out.println(jsonJAVA); //[{"id":1,"name":"广州"},{"id":2,"name":"珠海"}] } private static void set2json() { Set<City> citySet = new LinkedHashSet<City>(); citySet.add(new City(1,"广州")); citySet.add(new City(2,"珠海")); JSONArray jSONArray = JSONArray.fromObject(citySet); String jsonJAVA = jSONArray.toString(); System.out.println(jsonJAVA); //[{"id":1,"name":"广州"},{"id":2,"name":"珠海"}] } private static void javabeanlist2json() { List<City> cityList = new ArrayList<City>(); cityList.add(new City(1,"中山")); cityList.add(new City(2,"佛山")); Province province = new Province(1,"广东",cityList); JSONArray jSONArray = JSONArray.fromObject(province); String jsonJAVA = jSONArray.toString(); System.out.println(jsonJAVA); /* [ { "id":1, "name":"广东" "cityList":[{"id":1,"name":"中山"},{"id":2,"name":"佛山"}], } ] */ } private static void map2json() { List<City> cityList = new ArrayList<City>(); cityList.add(new City(1,"中山")); cityList.add(new City(2,"佛山")); Map<String,Object> map = new LinkedHashMap<String,Object>(); map.put("total",cityList.size());//表示集合的长度 map.put("rows",cityList);//rows表示集合 JSONArray jSONArray = JSONArray.fromObject(map); String jsonJAVA = jSONArray.toString(); System.out.println(jsonJAVA); //[{"total":2,"rows":[{"id":1,"name":"中山"},{"id":2,"name":"佛山"}]}] jsonJAVA = jsonJAVA.substring(1,jsonJAVA.length()-1); System.out.println(jsonJAVA); } } 把要解析成JSON 的javaBena对象、集合放进下面这段代码即可! JSONArray jSONArray = JSONArray.fromObject(map); 无论放进去什么,返回的都是数组 总结 如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章的同学,可以关注微信公众号:Java3y 更多的文章可往: 文章的目录导航

优秀的个人博客,低调大师

java入门(p1)进入java的世界

浅谈java世界(连载中P1) Java是一门语言,它并不是很难理解的东西,语言是来进行交流的工具,那么它用来跟谁来交互呢,所有的语言都有与其交流的对象,中文也好英文也罢,交流基本的对象应该有人对吧,那java呢?思考一下,当然是人与计算机了对吧,对,也就是电脑,那么问题来了(狄仁杰),人类在用语言沟通的时候,你看到了他们在交流,在沟通,你一句我一句的问答,双方的大脑都在解析着不同语言的含义,然后反映出要回答的话语. 那么java作为人与计算机交流的语言,人们写了一大堆代码扔给计算机,计算机也要去理解,计算机也需要一个理解java的大脑吧,这里引申一个新的名词(虚拟机JVM),虚拟机也就是理解java的大脑,它的作用是什么呢?想一想! 给一个小情景,一个来自印度的阿三大叔在撩来自四川的辣妹,毫无疑问的说两人都是有大脑的,如果没有那太可怕了,你觉得他会成功吗?起码我觉得语言不通是无法成功撩到小妹妹的,这个时候我们需要一个什么呢?翻译器对吧!我们要显得专业一些,这里引申一个新的名词(编译器),编译器的作用是什么呢?想一想! 相信小伙伴们已经大概理解java运行的原理了吧~我们写好了源代码,交给编译器翻译,将翻译好的东西交给虚拟机(JVM)运行就好了,红字部分是不是看起来特别不专业,翻译好的东西=字节码,字节码是虚拟机可以看懂的内容,那么问题来了,字节码是给谁看的呢?想一想! 我们来捋一捋java真正的java运行方式:** 源代码→编译器→字节码→java虚拟机(JVM)** **注:** 虚拟机的好处是它存在于你的机器中,你不需要去买一台java的机器,只要能用虚拟机就行了。 Java具有代表性的联合创始人是一个加拿大的软件工作者:James Gosling(詹姆斯高斯林) Java毕竟是老外发明出来的语言,英文单词很多,前期不要懵,多看看来来回回就那么点儿词汇,记住就行了,一点儿也不难。 关于java版本的问题就先不谈了,他们搞营销的脑子里都不知道在搞些什么,只要你不是用的远古版本,都可以满足你的初学需求。 问:源代码谁来写?谁来编译源代码?编译之后源代码变成了什么?谁去运行呢? 答:源代码由人类书写;编译器来编译源代码;在没有错误的情况下javac程序会将.java的文件编译成.class(它是由字节码组成的);字节码组成的.class文件会交给JVM(java虚拟机)去运行。 **一直很想做的事情开个头,欢迎指正。**

优秀的个人博客,低调大师

Python 数据科学入门教程:TensorFlow 目标检测

TensorFlow 目标检测 原文:TensorFlow Object Detection 译者:飞龙 协议:CC BY-NC-SA 4.0 一、引言 你好,欢迎阅读 TensorFlow 目标检测 API 迷你系列。 这个 API 可以用于检测图像和/或视频中的对象,带有使用边界框,使用可用的一些预先训练好的模型,或者你自己可以训练的模型(API 也变得更容易)。 首先,你要确保你有 TensorFlow 和所有的依赖。 对于 TensorFlow CPU,你可以执行pip install tensorflow,但是,当然,GPU 版本的 TensorFlow 在处理上要快得多,所以它是理想的。 如果你需要安装 TensorFlow GPU : 安装 TensorFlow GPU 的链接: Ubuntu Windows 如果你没有足够强大的 GPU 来运行 GPU 版本的 TensorFlow,则可以选择使用 PaperSpace。 使用该链接会给你 10 美元的起始折扣,10-20 小时的使用时间。 除此之外,其他的 Python 依赖包括: pip install pillow pip install lxml pip install jupyter pip install matplotlib 接下来,我们需要克隆 github。 我们可以使用git来完成,或者你可以将仓库下载到.zip: git clone https://github.com/tensorflow/models.git或者点击https://github.com/tensorflow/model页面上绿色的“克隆或下载”按钮,下载.zip并解压。 一旦你有了模型目录(或models-master,如果你下载并解压.zip),在你的终端或cmd.exe中访问这个目录。 在 Ubuntu 和 Windows 下的步骤略有不同。 Ubuntu: protoc object_detection/protos/*.proto --python_out=. 并且… export PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim 如果 Ubuntu 上的protoc命令出现错误,请使用protoc --version检查你运行的版本,如果它不是最新版本,你可能需要更新。 我写这个的时候,我们使用 3.4.0。 为了更新或获取protoc,请前往protoc发布页面。 下载 python 版本,解压,访问目录,然后执行: sudo ./configure sudo make check sudo make install 之后,再次尝试protoc命令(再次确保你在模型目录中执行)。 Windows 前往protoc发布页面并下载protoc-3.4.0-win32.zip,解压缩,然后在bin目录中找到protoc.exe。 如果你喜欢,你可以把它移到更合适的地方,或者把它放在这里。 我最终为我的程序文件生成protoc目录,并放在那里。 现在,从models(或models-master)目录中,可以使用protoc命令,如下所示: "C:/Program Files/protoc/bin/protoc" object_detection/protos/*.proto --python_out=. 接下来,从models/object_detection目录中打开terminal/cmd.exe,然后用jupyter notebook打开 Jupyter 笔记本。 从这里选择object_detection_tutorial.ipynb。 从这里,你应该能在主菜单中运行单元格,并选择全部运行。 你应该得到以下结果: 在下一个教程中,我们将介绍,如何通过稍微修改此示例代码,来实时标注来自网络摄像头流的数据。 二、视频流的目标检测 欢迎阅读 TensorFlow 目标检测 API 教程的第二部分。 在本教程中,我们将介绍如何调整 API 的 github 仓库中的示例代码,来将对象检测应用到来自摄像头的视频流。 首先,我们将首先修改笔记本,将其转换为.py文件。 如果你想保存在笔记本中,那也没关系。 为了转换,你可以访问file > save as > python file。 一旦完成,你需要注释掉get_ipython().magic('matplotlib inline')这一行。 接下来,我们将引入 Python OpenCV 包装器: 如果你没有安装 OpenCV,你需要获取它。 说明请参阅 OpenCV 简介。 import cv2 cap = cv2.VideoCapture(0) 这将准备cap变量来访问你的摄像头。 接下来,你将下面的代码: for image_path in TEST_IMAGE_PATHS: image = Image.open(image_path) # the array based representation of the image will be used later in order to prepare the # result image with boxes and labels on it. image_np = load_image_into_numpy_array(image) 替换为: while True: ret, image_np = cap.read() 最后将这些东西: plt.figure(figsize=IMAGE_SIZE) plt.imshow(image_np) plt.show() 替换为: cv2.imshow('object detection', cv2.resize(image_np, (800,600))) if cv2.waitKey(25) & 0xFF == ord('q'): cv2.destroyAllWindows() break 这就好了。完整代码: import numpy as np import os import six.moves.urllib as urllib import sys import tarfile import tensorflow as tf import zipfile from collections import defaultdict from io import StringIO from matplotlib import pyplot as plt from PIL import Image import cv2 cap = cv2.VideoCapture(1) # This is needed since the notebook is stored in the object_detection folder. sys.path.append("..") # ## Object detection imports # Here are the imports from the object detection module. # In[3]: from utils import label_map_util from utils import visualization_utils as vis_util # # Model preparation # ## Variables # # Any model exported using the `export_inference_graph.py` tool can be loaded here simply by changing `PATH_TO_CKPT` to point to a new .pb file. # # By default we use an "SSD with Mobilenet" model here. See the [detection model zoo](https://github.com/tensorflow/models/blob/master/object_detection/g3doc/detection_model_zoo.md) for a list of other models that can be run out-of-the-box with varying speeds and accuracies. # In[4]: # What model to download. MODEL_NAME = 'ssd_mobilenet_v1_coco_11_06_2017' MODEL_FILE = MODEL_NAME + '.tar.gz' DOWNLOAD_BASE = 'http://download.tensorflow.org/models/object_detection/' # Path to frozen detection graph. This is the actual model that is used for the object detection. PATH_TO_CKPT = MODEL_NAME + '/frozen_inference_graph.pb' # List of the strings that is used to add correct label for each box. PATH_TO_LABELS = os.path.join('data', 'mscoco_label_map.pbtxt') NUM_CLASSES = 90 # ## Download Model # In[5]: opener = urllib.request.URLopener() opener.retrieve(DOWNLOAD_BASE + MODEL_FILE, MODEL_FILE) tar_file = tarfile.open(MODEL_FILE) for file in tar_file.getmembers(): file_name = os.path.basename(file.name) if 'frozen_inference_graph.pb' in file_name: tar_file.extract(file, os.getcwd()) # ## Load a (frozen) Tensorflow model into memory. # In[6]: detection_graph = tf.Graph() with detection_graph.as_default(): od_graph_def = tf.GraphDef() with tf.gfile.GFile(PATH_TO_CKPT, 'rb') as fid: serialized_graph = fid.read() od_graph_def.ParseFromString(serialized_graph) tf.import_graph_def(od_graph_def, name='') # ## Loading label map # Label maps map indices to category names, so that when our convolution network predicts `5`, we know that this corresponds to `airplane`. Here we use internal utility functions, but anything that returns a dictionary mapping integers to appropriate string labels would be fine # In[7]: label_map = label_map_util.load_labelmap(PATH_TO_LABELS) categories = label_map_util.convert_label_map_to_categories(label_map, max_num_classes=NUM_CLASSES, use_display_name=True) category_index = label_map_util.create_category_index(categories) # ## Helper code # In[8]: def load_image_into_numpy_array(image): (im_width, im_height) = image.size return np.array(image.getdata()).reshape( (im_height, im_width, 3)).astype(np.uint8) # # Detection # In[9]: # For the sake of simplicity we will use only 2 images: # image1.jpg # image2.jpg # If you want to test the code with your images, just add path to the images to the TEST_IMAGE_PATHS. PATH_TO_TEST_IMAGES_DIR = 'test_images' TEST_IMAGE_PATHS = [ os.path.join(PATH_TO_TEST_IMAGES_DIR, 'image{}.jpg'.format(i)) for i in range(1, 3) ] # Size, in inches, of the output images. IMAGE_SIZE = (12, 8) # In[10]: with detection_graph.as_default(): with tf.Session(graph=detection_graph) as sess: while True: ret, image_np = cap.read() # Expand dimensions since the model expects images to have shape: [1, None, None, 3] image_np_expanded = np.expand_dims(image_np, axis=0) image_tensor = detection_graph.get_tensor_by_name('image_tensor:0') # Each box represents a part of the image where a particular object was detected. boxes = detection_graph.get_tensor_by_name('detection_boxes:0') # Each score represent how level of confidence for each of the objects. # Score is shown on the result image, together with the class label. scores = detection_graph.get_tensor_by_name('detection_scores:0') classes = detection_graph.get_tensor_by_name('detection_classes:0') num_detections = detection_graph.get_tensor_by_name('num_detections:0') # Actual detection. (boxes, scores, classes, num_detections) = sess.run( [boxes, scores, classes, num_detections], feed_dict={image_tensor: image_np_expanded}) # Visualization of the results of a detection. vis_util.visualize_boxes_and_labels_on_image_array( image_np, np.squeeze(boxes), np.squeeze(classes).astype(np.int32), np.squeeze(scores), category_index, use_normalized_coordinates=True, line_thickness=8) cv2.imshow('object detection', cv2.resize(image_np, (800,600))) if cv2.waitKey(25) & 0xFF == ord('q'): cv2.destroyAllWindows() break 我们可以清理更多代码,比如去掉matplotlib的导入,以及旧的图像数据,如果你喜欢的话,随意清理。 你应该有一个被标记的流媒体摄像头源。 一些可以测试的物体:自己,手机或者一瓶水。 所有这些应该有效。 在下一个教程中,我们将介绍如何添加我们自己的自定义对象来跟踪。 三、跟踪自定义对象 欢迎阅读 TensorFlow 目标检测 API 系列教程的第 3 部分。 在这部分以及随后的几部分中,我们将介绍如何使用此 API 跟踪和检测自己的自定义对象。 如果你观看视频,我正在使用 Paperspace。 如果你需要一个高端的 GPU,你可以使用他们的云桌面解决方案,这里有个推广链接能获得 10 美元的折扣,这足以完成这个迷你系列(训练时间约为 1 小时,GPU 为 0.40 美元/小时) 从使用预先建立的模型,到添加自定义对象,对于我的发现是个巨大跳跃,我找不到任何完整的一步一步的指导,所以希望我可以拯救你们于苦难。 一旦解决,训练任何你能想到的自定义对象(并为其创建数据)的能力,是一项了不起的技能。 好吧,简单介绍一下所需的步骤: 收集几百个包含你的对象的图像 - 最低限度是大约 100,理想情况下是 500+,但是,你有的图像越多,第二部就越乏味… 注释/标注你的图像,理想情况下使用程序。 我个人使用 LabelImg。 这个过程基本上是,在你图像的对象周围画框。 标注程序会自动创建一个描述图片中的对象的 XML 文件。 将这些数据分解成训练/测试样本 从这些分割生成 TF 记录 为所选模型设置.config文件(你可以从头自己开始训练,但是我们将使用迁移学习) 训练 从新的训练模型导出图形 实时检测自定义对象! … 完成! 所以,在本教程中,我需要一个对象。 我想要一些有用的东西,但还没有完成。 显然,每个人都需要知道通心粉和奶酪的位置,所以让我们跟踪它! 我使用 Google Images,Bing 和 ImageNet 来收集一些通心粉和奶酪的图像。 一般来说,图片大小在800x600左右,不能太大也不能太小。 对于本教程,你可以跟踪任何你想要的东西,只需要 100 多张图片。 一旦你有图像,你需要标注它们。 为此,我将使用 LabelImg,你可以使用git clone https://github.com/tzutalin/labelImg来获取它,或者直接下载并解压zip。 安装说明在labelimg github上,但对于 Ubuntu 上的 Python3: sudo apt-get install pyqt5-dev-tools sudo pip3 install lxml make qt5py3 python3 labelImg.py 运行这个时,你应该得到一个 GUI 窗口。 从这里,选择打开目录并选择你保存所有图像的目录。 现在,你可以开始使用创建rectbox按钮进行注释。 绘制你的框,添加名称,并点击确定。 保存,点击下一张图片,然后重复! 你可以按w键来画框,并按ctrl + s来保存得更快。 不确定是否有下一张图片的快捷键。 一旦你标记了超过 100 张图片被,我们将把他们分成训练和测试组。 为此,只需将你的图像和注解 XML 文件的约 10% 复制到一个称为test的新目录,然后将其余的复制到一个叫做train的新目录。 一旦完成了所有这些,就可以开始下一个教程了,我们将介绍如何从这些数据创建所需的 TFRecord 文件。 另外,如果你想使用我的预制文件,你可以下载我的已标注的通心粉和奶酪。 四、创建 TFRecord 欢迎阅读 TensorFlow 目标检测 API 系列教程的第 4 部分。在本教程的这一部分,我们将介绍如何创建 TFRecord 文件,我们需要它来训练对象检测模型。 到了这里,你应该有一个图像目录,里面有所有的图像,以及 2 个额外的目录:训练和测试。在测试目录内应该是你的图像的月 10% 的副本与他们的 XML 注释数据,然后训练目录应该有其余的副本。如果你没有,请转到上一个教程。 现在我们需要将这些 XML 文件转换为单个 CSV 文件,它们可以转换为 TFRecord 文件。为此,我将利用datitran的 github 中的一些代码做一些小的改动。首先,我们要使用xml_to_csv.py。你既可以克隆他的整个目录,也可以抓取这些文件,我们将使用其中的两个。由于他的存储库已经改变了多次,我已经搞乱了,我注意到,我所使用的具体提交是:这个。如果这两个脚本中的任何一个都不适合你,请尝试拉取和我相同的提交。绝对要尝试他的最新版本。例如,在我写这个的时候,他刚刚更新了图像中的多个盒标签,这显然是一个非常有用的改进。 在xml_to_csv脚本中,我将: def main(): image_path = os.path.join(os.getcwd(), 'annotations') xml_df = xml_to_csv(image_path) xml_df.to_csv('raccoon_labels.csv', index=None) print('Successfully converted xml to csv.') 修改为: def main(): for directory in ['train','test']: image_path = os.path.join(os.getcwd(), 'images/{}'.format(directory)) xml_df = xml_to_csv(image_path) xml_df.to_csv('data/{}_labels.csv'.format(directory), index=None) print('Successfully converted xml to csv.') 这只是拆分训练/测试和命名文件的有用的东西。 继续并创建一个数据目录,然后运行它来创建这两个文件。 接下来,在主对象检测目录中创建一个训练目录。 到了这里,你应该有以下结构,它在我的桌面上: Object-Detection -data/ --test_labels.csv --train_labels.csv -images/ --test/ ---testingimages.jpg --train/ ---testingimages.jpg --...yourimages.jpg -training -xml_to_csv.py 现在,抓取generate_tfrecord.py。 你需要做的唯一修改在class_text_to_int函数中。 你需要改变你的具体类别。 在我们的例子中,我们只有一个类别。 如果你有很多类别,那么你需要继续构建这个if语句。 # TO-DO replace this with label map def class_text_to_int(row_label): if row_label == 'macncheese': return 1 else: None 从 TODO 来看,这个函数在将来可能会有一些变化,所以再一次使用你的直觉来修改最新版本,或者使用我正在使用的同一个提交。 接下来,为了使用它,我们需要在 github 克隆的模型目录内运行,或者可以更正式地安装对象检测 API。 我正在在一个新的机器上的做这个教程,来确保我不会错过任何步骤,所以我将完整配置对象的 API。 如果你已经克隆和配置,可以跳过最初的步骤,选择setup.py部分! 首先,我将仓库克隆到我的桌面上: git clone https://github.com/tensorflow/models.git 之后,遵循以下安装指令: sudo apt-get install protobuf-compiler python-pil python-lxml sudo pip install jupyter sudo pip install matplotlib 之后: # From tensorflow/models/ protoc object_detection/protos/*.proto --python_out=. 如果 Ubuntu 上的protoc命令出现错误,请使用protoc --version检查你运行的版本,如果它不是最新版本,你可能需要更新。 我写这个的时候,我们使用 3.4.0。 为了更新或获取protoc,请前往protoc发布页面。 下载 python 版本,解压,访问目录,然后执行: sudo ./configure sudo make check sudo make install 之后,再次尝试protoc命令(再次确保你在模型目录中执行)。 并且 # From tensorflow/models/ export PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim 最后,我们通过在models目录中执行以下步骤,来正式安装object_dection库: sudo python3 setup.py install 现在我们可以运行generate_tfrecord.py脚本。 我们将运行两次,一次用于训练 TFRecord,一次用于测试 TFRecord。 python3 generate_tfrecord.py --csv_input=data/train_labels.csv --output_path=data/train.record python3 generate_tfrecord.py --csv_input=data/test_labels.csv --output_path=data/test.record 现在,在你的数据目录中,你应该有train.record和test.record。 接下来,我们需要设置一个配置文件,然后训练一个新的模型,或者从一个预先训练好的模型的检查点开始,这将在下一个教程中介绍。 五、训练自定义对象检测器 欢迎阅读 TensorFlow 对象检测 API 系列教程的第 5 部分。在本教程的这一部分,我们将训练我们的对象检测模型,来检测我们的自定义对象。为此,我们需要匹配 TFRecords 的训练和测试数据的图像,然后我们需要配置模型,然后我们可以训练。对我们来说,这意味着我们需要设置一个配置文件。 在这里,我们有两个选择。我们可以使用预训练的模型,然后使用迁移学习来习得一个新的对象,或者我们可以从头开始习得新的对象。迁移学习的好处是训练可能更快,你需要的数据可能少得多。出于这个原因,我们将在这里执行迁移学习。 TensorFlow 有相当多的预训练模型,带有检查点文件和配置文件。如果你喜欢,可以自己完成所有这些工作,查看他们的配置作业文档。对象 API 还提供了一些示例配置供你选择。 我打算使用 mobilenet,使用下面的检查点和配置文件: wget https://raw.githubusercontent.com/tensorflow/models/master/object_detection/samples/configs/ssd_mobilenet_v1_pets.config wget http://download.tensorflow.org/models/object_detection/ssd_mobilenet_v1_coco_11_06_2017.tar.gz 你可以查看一些其他检查点选项,来从这里起步。 将该配置放在训练目录中,并解压models/object_detection目录中的ssd_mobilenet_v1。 在配置文件中,你需要搜索所有PATH_TO_BE_CONFIGURED的位置并更改它们。 你可能还想要修改批量大小。 目前,我的配置文件中设置为 24。 其他模型可能有不同的批量。 如果出现内存错误,可以尝试减小批量以使模型适合你的 VRAM。 最后,还需要修改检查点名称/路径,将num_classes更改为 1,num_examples更改为 12,以及label_map_path改为"training/object-detect.pbtxt"。 这是一些编辑,所以这里是我的完整的配置文件: # SSD with Mobilenet v1, configured for the mac-n-cheese dataset. # Users should configure the fine_tune_checkpoint field in the train config as # well as the label_map_path and input_path fields in the train_input_reader and # eval_input_reader. Search for "${YOUR_GCS_BUCKET}" to find the fields that # should be configured. model { ssd { num_classes: 1 box_coder { faster_rcnn_box_coder { y_scale: 10.0 x_scale: 10.0 height_scale: 5.0 width_scale: 5.0 } } matcher { argmax_matcher { matched_threshold: 0.5 unmatched_threshold: 0.5 ignore_thresholds: false negatives_lower_than_unmatched: true force_match_for_each_row: true } } similarity_calculator { iou_similarity { } } anchor_generator { ssd_anchor_generator { num_layers: 6 min_scale: 0.2 max_scale: 0.95 aspect_ratios: 1.0 aspect_ratios: 2.0 aspect_ratios: 0.5 aspect_ratios: 3.0 aspect_ratios: 0.3333 } } image_resizer { fixed_shape_resizer { height: 300 width: 300 } } box_predictor { convolutional_box_predictor { min_depth: 0 max_depth: 0 num_layers_before_predictor: 0 use_dropout: false dropout_keep_probability: 0.8 kernel_size: 1 box_code_size: 4 apply_sigmoid_to_scores: false conv_hyperparams { activation: RELU_6, regularizer { l2_regularizer { weight: 0.00004 } } initializer { truncated_normal_initializer { stddev: 0.03 mean: 0.0 } } batch_norm { train: true, scale: true, center: true, decay: 0.9997, epsilon: 0.001, } } } } feature_extractor { type: 'ssd_mobilenet_v1' min_depth: 16 depth_multiplier: 1.0 conv_hyperparams { activation: RELU_6, regularizer { l2_regularizer { weight: 0.00004 } } initializer { truncated_normal_initializer { stddev: 0.03 mean: 0.0 } } batch_norm { train: true, scale: true, center: true, decay: 0.9997, epsilon: 0.001, } } } loss { classification_loss { weighted_sigmoid { anchorwise_output: true } } localization_loss { weighted_smooth_l1 { anchorwise_output: true } } hard_example_miner { num_hard_examples: 3000 iou_threshold: 0.99 loss_type: CLASSIFICATION max_negatives_per_positive: 3 min_negatives_per_image: 0 } classification_weight: 1.0 localization_weight: 1.0 } normalize_loss_by_num_matches: true post_processing { batch_non_max_suppression { score_threshold: 1e-8 iou_threshold: 0.6 max_detections_per_class: 100 max_total_detections: 100 } score_converter: SIGMOID } } } train_config: { batch_size: 10 optimizer { rms_prop_optimizer: { learning_rate: { exponential_decay_learning_rate { initial_learning_rate: 0.004 decay_steps: 800720 decay_factor: 0.95 } } momentum_optimizer_value: 0.9 decay: 0.9 epsilon: 1.0 } } fine_tune_checkpoint: "ssd_mobilenet_v1_coco_11_06_2017/model.ckpt" from_detection_checkpoint: true data_augmentation_options { random_horizontal_flip { } } data_augmentation_options { ssd_random_crop { } } } train_input_reader: { tf_record_input_reader { input_path: "data/train.record" } label_map_path: "data/object-detection.pbtxt" } eval_config: { num_examples: 40 } eval_input_reader: { tf_record_input_reader { input_path: "data/test.record" } label_map_path: "training/object-detection.pbtxt" shuffle: false num_readers: 1 } 在训练目录里面,添加object-detection.pbtxt: item { id: 1 name: 'macncheese' } 而现在,见证奇迹时刻! 在models/object_detection中: python3 train.py --logtostderr --train_dir=training/ --pipeline_config_path=training/ssd_mobilenet_v1_pets.config 禁止错误,你应该看到如下输出: INFO:tensorflow:global step 11788: loss = 0.6717 (0.398 sec/step) INFO:tensorflow:global step 11789: loss = 0.5310 (0.436 sec/step) INFO:tensorflow:global step 11790: loss = 0.6614 (0.405 sec/step) INFO:tensorflow:global step 11791: loss = 0.7758 (0.460 sec/step) INFO:tensorflow:global step 11792: loss = 0.7164 (0.378 sec/step) INFO:tensorflow:global step 11793: loss = 0.8096 (0.393 sec/step) 你的步骤从1开始,损失会高一些。 根据你的 GPU 和你有多少训练数据,这个过程需要不同的时间。 像 1080ti 这样的东西,应该只需要一个小时左右。 如果你有很多训练数据,则可能需要更长的时间。 你想截取的损失平均约为 1(或更低)。 我不会停止训练,直到你确定在 2 以下。你可以通过 TensorBoard 检查模型如何训练。 你的models/object_detection/training目录中会出现新的事件文件,可以通过 TensorBoard 查看。 在models/object_detection中通过终端,这样启动 TensorBoard: tensorboard --logdir='training' 这会运行在127.0.0.1:6006(在浏览器中访问); 我的总损失图: 看起来不错,但它能检测通心粉和奶酪嘛?! 为了使用模型来检测事物,我们需要导出图形,所以在下一个教程中,我们将导出图形,然后测试模型。 六、测试自定义对象检测器 欢迎阅读 TensorFlow 对象检测 API 教程系列的第 6 部分。 在本教程的这一部分,我们将测试我们的模型,看看它是否符合我们的希望。 为此,我们需要导出推理图。 幸运的是,在models/object_detection目录中,有一个脚本可以帮助我们:export_inference_graph.py 为了运行它,你只需要传入你的检查点和你的流水线配置,然后是你想放置推理图的任何地方。 例如: python3 export_inference_graph.py \ --input_type image_tensor \ --pipeline_config_path training/ssd_mobilenet_v1_pets.config \ --trained_checkpoint_prefix training/model.ckpt-10856 \ --output_directory mac_n_cheese_inference_graph 你的检查点文件应该在训练目录中。 只要找出最大步骤(破折号后面最大的那个),那就是你想要使用的那个。 接下来,确保pipeline_config_path设置为你选择的任何配置文件,然后最后选择输出目录的名称,我用mac_n_cheese_inference_graph。 在models/object_detection中运行上述命令。 如果你得到一个错误,没有名为nets的模块,那么你需要重新运行: # From tensorflow/models/ export PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim # switch back to object_detection after this and re run the above command 否则,你应该有一个新的目录,在我的情况下,我的是mac_n_cheese_inference_graph,里面,我有新的检查点数据,saved_model目录,最重要的是,forzen_inference_graph.pb文件。 现在,我们将使用示例笔记本,对其进行编辑,并查看我们的模型在某些测试图像上的工作情况。 我将一些models/object_detection/images/test images图像复制到models/object_detection/test_images目录中,并将其更名为image3.jpg,image4.jpg…等。 启动 jupyter 笔记本并打开object_detection_tutorial.ipynb,让我们进行一些更改。 首先,前往“变量”部分,然后更改模型名称以及检查点和标签的路径: # What model to download. MODEL_NAME = 'mac_n_cheese_inference_graph' # Path to frozen detection graph. This is the actual model that is used for the object detection. PATH_TO_CKPT = MODEL_NAME + '/frozen_inference_graph.pb' # List of the strings that is used to add correct label for each box. PATH_TO_LABELS = os.path.join('training', 'object-detection.pbtxt') NUM_CLASSES = 1 接下来,我们可以删除整个下载模型部分,因为我们不需要再下载了。 最后,在“检测”部分中,将TEST_IMAGE_PATHS变量更改为: TEST_IMAGE_PATHS = [ os.path.join(PATH_TO_TEST_IMAGES_DIR, 'image{}.jpg'.format(i)) for i in range(3, 8) ] 有了这个,你可以访问单元格菜单选项,然后“运行全部”。 以下是我的一些结果: 总的来说,我非常高兴看到它的效果有多棒,即使你有一个非常小的数据集,你仍然可以成功。使用迁移学习来训练一个模型只需要一个小时(在一个像样的 GPU 上)。 很酷!

优秀的个人博客,低调大师

菜鸟入门【ASP.NET Core】1:环境安装

下载.NET Core SDK 下载地址:https://www.microsoft.com/net/download/windows https://www.microsoft.com/net/learn/get-started/windows 安装vs2017,安装的时候选择安装core跨平台 在程序安装后,可以在控制台输入dotnet进行创建core应用程序 输入dotnet --help查看命令帮助 .NET 命令行工具 (2.1.2) 使用情况: dotnet [runtime-options] [path-to-application] 使用情况: dotnet [sdk-options] [command] [arguments] [command-options] path-to-application: 要执行的应用程序 .dll 文件的路径。 SDK 命令: new 初始化 .NET 项目。 restore 还原 .NET 项目中指定的依赖项。 run 编译并立即执行 .NET 项目。 build 生成 .NET 项目。 publish 发布 .NET 项目以进行部署(包括运行时)。 test 使用项目中指定的测试运行程序运行单元测试。 pack 创建 NuGet 包。 migrate 将基于 project.json 的项目迁移到基于 MSBuild 的项目。 clean 清除生成输出。 sln 修改解决方案(SLN)文件。 add 将引用添加到项目中。 remove 从项目中删除引用。 list 列出项目中的引用。 nuget 提供其他 NuGet 命令。 msbuild 运行 Microsoft 生成引擎 (MSBuild)。 vstest 运行 Microsoft 测试执行命令行工具。 常用选项: -v|--verbosity 设置命令的详细级别。允许值为 q[uiet]、m[inimal]、n[ormal]、d[etailed] 和 diag[nostic]。 -h|--help 显示帮助。 运行“dotnet 命令 --help”,获取有关命令的详细信息。 sdk-options: --version 显示 .NET Core SDK 版本。 --info 显示 .NET Core 信息。 -d|--diagnostics 启用诊断输出。 runtime-options: --additionalprobingpath <path> 要探测的包含探测策略和程序集的路径。 --fx-version <version> 要用于运行应用程序的安装版共享框架的版本。 --roll-forward-on-no-candidate-fx 已启用“不前滚到候选共享框架”。 --additional-deps <path> 其他 deps.json 文件的路径。 输入dotnet new --help查看初始化.net项目命令帮助 Microsoft Windows [版本 6.1.7601] 版权所有 (c) 2009 Microsoft Corporation。保留所有权利。 C:\Users\Administrator>dotnet Usage: dotnet [options] Usage: dotnet [path-to-application] Options: -h|--help Display help. --version Display version. path-to-application: The path to an application .dll file to execute. C:\Users\Administrator>dotnet new --help 欢迎使用 .NET Core! --------------------- 若要详细了解 .NET Core,请访问 https://aka.ms/dotnet-docs。使用 dotnet --help 查 看可用的命令或转到 https://aka.ms/dotnet-cli-docs。 遥测 -------------- .NET Core 收集使用情况数据,以便改善用户体验。数据是匿名的且不包含命令行参数。数 据由 Microsoft 收集,并与社区共享。 可选择使用你最喜爱的 shell 将 DOTNET_CLI_TELEMETRY_OPTOUT 环境变量设置为 1,从而 退出遥测。 若要深入了解 .NET Core 工具遥测,请访问 https://aka.ms/dotnet-cli-telemetry。 正在准备... 使用情况: new [选项] 选项: -h, --help 显示有关此命令的帮助。 -l, --list 列出包含指定名称的模板。如果未指定名称,请列出所有模板。 -n, --name 正在创建输出的名称。如果未指定任何名称,将使用当前目录的名 称。 -o, --output 要放置生成的输出的位置。 -i, --install 安装源或模板包。 -u, --uninstall 卸载一个源或模板包。 --type 基于可用的类型筛选模板。预定义的值为 "project"、"item" 或 "other"。 --force 强制生成内容,即使该内容会更改现有文件。 -lang, --language 指定要创建的模板的语言。 使用情况: new [选项] 选项: -h, --help 显示有关此命令的帮助。 -l, --list 列出包含指定名称的模板。如果未指定名称,请列出所有模板。 -n, --name 正在创建输出的名称。如果未指定任何名称,将使用当前目录的名 称。 -o, --output 要放置生成的输出的位置。 -i, --install 安装源或模板包。 -u, --uninstall 卸载一个源或模板包。 --type 基于可用的类型筛选模板。预定义的值为 "project"、"item" 或 "other"。 --force 强制生成内容,即使该内容会更改现有文件。 -lang, --language 指定要创建的模板的语言。 模板 短名称 语言 标记 -------------------------------------------------------------------------------- ------------------------ Console Application console [C#], F#, VB Common/Console Class library classlib [C#], F#, VB Common/Library Unit Test Project mstest [C#], F#, VB Test/MSTest xUnit Test Project xunit [C#], F#, VB Test/xUnit ASP.NET Core Empty web [C#], F# Web/Empty ASP.NET Core Web App (Model-View-Controller) mvc [C#], F# Web/MVC ASP.NET Core Web App razor [C#] Web/MVC/Razor Pages ASP.NET Core with Angular angular [C#] Web/MVC/SPA ASP.NET Core with React.js react [C#] Web/MVC/SPA ASP.NET Core with React.js and Redux reactredux [C#] Web/MVC/SPA ASP.NET Core Web API webapi [C#], F# Web/WebAPI global.json file globaljson Config NuGet Config nugetconfig Config Web Config webconfig Config Solution File sln Solution Razor Page page Web/ASP.NET MVC ViewImports viewimports Web/ASP.NET MVC ViewStart viewstart Web/ASP.NET Examples: dotnet new mvc --auth Individual dotnet new classlib --framework netcoreapp2.0 dotnet new --help C:\Users\Administrator> 使用dotnet new mvc创建一个mvc项目 这时候已经创建好了项目,可以用vsual studio code打开 可以用命令dotnet run运行刚刚新建的程序 访问http://localhost:5000进行访问 vs2017创建CORE应用程序 选择:文件----新建----项目 启动不推荐使用iis,推荐使用控制台启动

优秀的个人博客,低调大师

Docker 从入门到放弃(二)容器使用

Docker 容器使用 一、Docker 客户端 docker客户端非常简单,我们可以直接输入docker命令来查看到 Docker 客户端的所有命令选项。 root@iZ235mi4a64Z:~# docker Usage: docker COMMAND A self-sufficient runtime for containers Options: --config string Location of client config files (default "/root/.docker") -D, --debug Enable debug mode -H, --host list Daemon socket(s) to connect to -l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info") --tls Use TLS; implied by --tlsverify --tlscacert string Trust certs signed only by this CA (default "/root/.docker/ca.pem") --tlscert string Path to TLS certificate file (default "/root/.docker/cert.pem") --tlskey string Path to TLS key file (default "/root/.docker/key.pem") --tlsverify Use TLS and verify the remote -v, --version Print version information and quit Management Commands: config Manage Docker configs container Manage containers image Manage images ... 可以通过命令 docker command --help 更深入的了解指定的 Docker 命令使用方法。 例如要查看 docker stats 指令的具体使用方法: root@iZ235mi4a64Z:~# docker stats --help Usage: docker stats [OPTIONS] [CONTAINER...] Display a live stream of container(s) resource usage statistics Options: -a, --all Show all containers (default shows just running) --format string Pretty-print images using a Go template --no-stream Disable streaming stats and only pull the first result --no-trunc Do not truncate output 二、运行一个web应用 前面我们运行的容器并没有一些什么特别的用处。接下来让我们尝试使用 docker 构建一个 web 应用程序。我们将在docker容器中运行一个 Python Flask 应用来运行一个web应用。 第一次使用,本地是没有镜像的,所有要下载远程仓库镜像 参数说明: -d:让容器在后台运行。 -P:将容器内部使用的网络端口映射到我们使用的主机上。 root@iZ235mi4a64Z:~# docker run -d -P training/webapp python app.py Unable to find image 'training/webapp:latest' locally latest: Pulling from training/webapp e190868d63f8: Pull complete 909cd34c6fd7: Pull complete 0b9bfabab7c1: Pull complete a3ed95caeb02: Pull complete 10bbbc0fc0ff: Pull complete fca59b508e9f: Pull complete e7ae2541b15b: Pull complete 9dd97ef58ce9: Pull complete a4c1b0cb7af7: Pull complete Digest: sha256:06e9c1983bd6d5db5fba376ccd63bfa529e8d02f23d5079b8f74a616308fb11d Status: Downloaded newer image for training/webapp:latest d83ffc50991fabc9aedee521be91329048bf0f17b4ca3f90cf20b63209cfbdd2 root@iZ235mi4a64Z:~# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d83ffc50991f training/webapp "python app.py" 8 minutes ago Up 8 minutes 0.0.0.0:32768->5000/tcp adoring_jackson 下载好后会默认启动该容器 三、查看 WEB 应用容器 使用docker ps来查看我们正在运行的容器 root@iZ235mi4a64Z:~# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d83ffc50991f training/webapp "python app.py" 8 minutes ago Up 8 minutes 0.0.0.0:32768->5000/tcp adoring_jackson Docker 开放了 5000 端口(默认 Python Flask 端口)映射到主机端口 32768 上。 这时我们可以通过浏览器访问WEB应用 我们也可以指定 -p 标识来绑定指定端口 root@iZ235mi4a64Z:~# docker run -d -p 5000:5000 training/webapp python app.py ebdeda041b1e97850337c8a514dd7163db740a8eb82e8b7270402095a6368fa2 root@iZ235mi4a64Z:~# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ebdeda041b1e training/webapp "python app.py" 5 seconds ago Up 3 seconds 0.0.0.0:5000->5000/tcp condescending_austin d83ffc50991f training/webapp "python app.py" 16 minutes ago Up 16 minutes 0.0.0.0:32768->5000/tcp adoring_jackson root@iZ235mi4a64Z:~# curl http://127.0.0.1:5000 Hello world! 容器内部的 5000 端口映射到我们本地主机的 5000 端口上 四、网络端口的快捷方式 通过docker ps 命令可以查看到容器的端口映射,docker还提供了另一个快捷方式:docker port,使用 docker port 可以查看指定 (ID或者名字)容器的某个确定端口映射到宿主机的端口号。 上面创建的web应用容器ID为:d83ffc50991f 名字为:adoring_jackson 可以使用docker port 7a38a1ad55c6 或docker port determined_swanson来查看容器端口的映射情况 root@iZ235mi4a64Z:~# docker port d83ffc50991f 5000/tcp -> 0.0.0.0:32768 root@iZ235mi4a64Z:~# docker port adoring_jackson 5000/tcp -> 0.0.0.0:32768 五、查看WEB应用程序日志 docker logs [ID或者名字] 可以查看容器内部的标准输出。 root@iZ235mi4a64Z:~# docker logs -f d83ffc50991f * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit) 192.168.0.1 - - [05/Dec/2017 02:00:32] "GET / HTTP/1.1" 200 - 192.168.0.1 - - [05/Dec/2017 02:01:55] "GET / HTTP/1.1" 200 - 192.168.0.1 - - [05/Dec/2017 02:02:11] "GET / HTTP/1.1" 200 - 192.168.0.1 - - [05/Dec/2017 02:02:18] "GET / HTTP/1.1" 200 - 192.168.0.1 - - [05/Dec/2017 02:02:23] "GET / HTTP/1.1" 200 - -f:让 dokcer logs 像使用 tail -f 一样来输出容器内部的标准输出。 从上面,可以看到应用程序使用的是 5000 端口并且能够查看到应用程序的访问日志。 六、查看WEB应用程序容器的进程 可以使用docker top来查看容器内部运行的进程 root@iZ235mi4a64Z:~# docker top 1c0efc43c0e5 UID PID PPID C STIME TTY TIME CMD root 25066 25050 0 10:19 ? 00:00:00 python app.py 七、检查WEB应用程序 使用 docker inspect 来查看Docker的底层信息。它会返回一个 JSON 文件记录着 Docker 容器的配置和状态信息。 root@iZ235mi4a64Z:~# docker inspect 1c0efc43c0e5 [ { "Id": "1c0efc43c0e5207b6eaa63270834562a5193820436ba80de3fdd8dfa1b77c764", "Created": "2017-12-05T02:19:12.557365261Z", "Path": "python", "Args": [ "app.py" ], "State": { "Status": "running", "Running": true, "Paused": false, "Restarting": false, "OOMKilled": false, "Dead": false, "Pid": 25066, "ExitCode": 0, "Error": "", "StartedAt": "2017-12-05T02:19:12.913440347Z", "FinishedAt": "0001-01-01T00:00:00Z" }, "Image": "sha256:6fae60ef344644649a39240b94d73b8ba9c67f898ede85cf8e947a887b3e6557", "ResolvConfPath": "/var/lib/docker/containers/1c0efc43c0e5207b6eaa63270834562a5193820436ba80de3fdd8dfa1b77c764/resolv.conf", ... 八、停止、重启WEB应用容器 root@iZ235mi4a64Z:~# docker stop relaxed_jones relaxed_jones root@iZ235mi4a64Z:~# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES root@iZ235mi4a64Z:~# docker start relaxed_jones relaxed_jones root@iZ235mi4a64Z:~# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1c0efc43c0e5 training/webapp "python app.py" 6 minutes ago Up 2 seconds 0.0.0.0:32770->5000/tcp relaxed_jones docker ps -l 查询最后一次创建的容器: root@iZ235mi4a64Z:~# docker ps -l CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1c0efc43c0e5 training/webapp "python app.py" 6 minutes ago Up 47 seconds 0.0.0.0:32770->5000/tcp relaxed_jones 九、移除WEB应用容器 使用 docker rm 命令来删除不需要的容器,删除容器时,容器必须是停止状态,否则会报如下错误 root@iZ235mi4a64Z:~# docker rm relaxed_jones Error response from daemon: You cannot remove a running container 1c0efc43c0e5207b6eaa63270834562a5193820436ba80de3fdd8dfa1b77c764. Stop the container before attempting removal or force remove 先停止后删除 root@iZ235mi4a64Z:~# docker stop relaxed_jones relaxed_jones root@iZ235mi4a64Z:~# docker rm relaxed_jones relaxed_jones

优秀的个人博客,低调大师

VSphere入门之vCenter的安装及基本管理

VMware vCenter Server是vSphere平台中最重要部分,是整个vSphere平台的中心,它可以从单一控制的点管理所有vSphere的ESXi主机和虚拟机,并且可以提供详细的虚拟架构信息,进行大规模管理,极大地提高了管理员对虚拟环境的控制能力 通过上一篇博客,我们使用vClient管理ESXi主机,但是只能实现一些如创建虚拟机的简单功能,而vSphere中的高级功能都无法实现。更重要的是,多台ESXi主机无法进行统一管理。下面是vCenterServer的多台主机管理与ESXi主机管理的比较: 1、什么是vCenter Server vCenter Server是vSphere解决方案基础物理架构的核心,可以提供如访问控制、性能监控、配置功能等,并且可以将多台ESXi主机资源集中,使这些资源在整个数据中心中的虚拟机之间共享。vCenter是一种服务,充当连接到网络的ESXi主机的中心管理员 2、安装vCenter Server前所必备的三大组件 (1)vCenter Single Singn-On 他是从vSphere5.1开始提出的身份验证服务,允许所有的vSphere软件组件通过安全的令牌交换机制相互通信,而不需要每个组件分别对用户进行身份验证,从而使VMware云基础架构平台更加安全 (2)vCenter Inventory Service 清单服务,用于存储vCenter Server应用程序和清单数据,使跨链接的vCenter Server可以搜索和访问清单对象 (3)vSphere Web vClient 一款使用Web浏览器通过vCenter Server管理ESXi主机的应用程序,并且所有的vSphere5.0以上新增的功能集都必须通过vSphere Web vClient才可以使用 3、安装vCenter Server 可以在台式机或笔记本电脑上安装vCenter Server,但必须是Windows系统的计算机上安装,且该计算机必须能够通过网络访问ESXi主机。如果是供生产使用,VMware建议将vCenter Server安装在专用服务器系统上。 在安装vCenter Server之前,请确保系统满足最低硬件和软件要求。vCenter Server需要数据库服务。VMware支持多种Oracle和Microsoft SQL Server数据库。 案例:如下图所示,完成vCenter Server的安装,并管理两台ESXi主机 注意:本案例使用的vCenter Server安装光盘是V5.5版,可通过登陆http://www.vmware.com/cn进行下载,所有服务器都需要配置填写DNS,除了ESXi主机,都需要加入yangshufan.com域 1.准备数据库 (1)本案例采用SQL Server 2008R2数据库,打开DBsvr服务器中“SQL Server配置管理器”,单击“SQL Server服务”,将所有服务的登陆身份改为“域管理员”,启动模式改为“自动并启动”,其中ReportServer的启动模式改为“禁用并停止”,如下图所示。这种方式仅适用于本案例,实际项目中需要根据实际情况配置 (2)打开并启用网络配置、协议、TCP/IP,在IP选项卡改为下图所示: (3)重启“SQL Server服务”,使上面配置生效 (4)创建一个用于vCenter Server的数据库“yang” (5)在SQL Server 2008R2光盘找到“sqlncli”安装,路径如下图所示: (6)在vCenter Server服务器打开管理工具,找到数据源(ODBC),创建数据源,如下图所示 (7)创建名称,选择数据库服务器,下一步 (8)输入准备好的vCenter Server数据库的管理员和密码,下一步 (9)选择准备好的vCenter Server数据库,完成与数据库间的连接 2.安装vCenter Single Singn-On (1)打开vCenter Server安装光盘的引导程序,选好程序,安装 (2)根据安装向导提示,进行设置密码,注意:密码不得少于8位,至少包含小写字符、大写字符、数字、特殊字符 (3)根据安装向导提示,即可完成安装 3.安装vCenter Inventory Service (1)打开vCenter Server安装光盘的引导程序,选择清单服务,安装 (2)根据安装向导提示,输入刚才创建的SSO密码 (3)根据安装向导提示,完成安装 4.安装vCenter Service (1)打开vCenter Server安装光盘的引导程序,安装 (2)根据安装向导提示,这里输入许可证密钥,不输入有60天的评估模式 (3)根据安装向导提示,如果安装SQLServer 2008 Express实例(用于小规模部署),此数据库适用于最多5个主机和50个虚拟机的小型部署。这里找到刚建好的数据库,下一步 (4)根据安装向导提示,这里可以输入用户和组,本案例是管理员组 (5)根据安装向导提示,完成安装 5.安装vSphere Web vClient (1)Web vClient要求安装Adobe Flash Player插件,下表是Web vClient的最低硬件配置: 硬件 配置说明 CPU 2.0GHz四核处理器 内存 至少2GB 硬盘 至少2GB的可以磁盘空间 网络 千兆网络 (2)打开vCenter Server安装光盘的引导程序,安装 (3)根据安装向导提示,完成安装 6.许可vCenter Service和ESXi (1)在vClient服务器上打开Web浏览器,输入 https://ysf.yangshufan.com:9443,进行访问 (2)下载客户端集成插件,完成安装 (3)安装完成,登陆后新建数据中心,添加主机 (4)可以把两台ESXi主机添加到一个数据中心,进行ESXi集中式管理 至此,已经完成了vCenter Server 5.5的安装,并且可对多台ESXi进行集中式管理了 本文转自 杨书凡 51CTO博客,原文链接:http://blog.51cto.com/yangshufan/1969365,如需转载请自行联系原作者

优秀的个人博客,低调大师

Windows 2008从入门到精通系列教程(二)

了解了Windows 2008的十大新功能,我相信大家已经迫不及待的想要去安装一个Windows 2008服务器来试用了。建议朋友们可以在虚拟机里面安装Windows 2008 R2,我这里使用的是VM。 Windows 2008 R2大致有四种安装方式,这里将一一讲解不同的安装方式。 1.升级安装:Windows 2008 R2的升级安装是针对Windows 2003的,下列Windows版本不能升级到2008 R2: Windows 95, Windows 98, Windows ME, Windows XP, Windows Vista 和 Windows 7 Windows NT Server 4.0, Windows 2000 Server, Windows Server 2003 RTM, Windows Server 2003 SP1, Windows Server 2003 Web和Windows Server 2008 R2 Beta Windows Server 2003 IA64, Windows Server 2003 x64, Windows Server 2008 IA64 不支持跨架构进行升级(例如,X86不能被升级到X64) 不支持跨语言进行升级(例如,英文版不能被升级成中文版) 不支持跨版本进行升级(例如,Windows Server 2008 Foundation不能被升级到Windows Server 2008 数据中心版) 支持的升级安装方式 从Windows Server 2003 (SP2, R2) 升级到Windows Server 2008 R2 数据中心版 数据中心版 企业版 企业版和数据中心版 标准版标准版和企业版 从Windows Server 2008 (RTM-SP1, SP2) 升级到Windows Server 2008 R2 数据中心版 数据中心版 数据中心版核心 数据中心版核心 企业版 企业版和数据中心版 企业版核心企业版核心和数据中心版核心 Foundation (SP2) 标准版 标准版 标准版和企业版 标准版核心标准版核心和企业版核心 Web版 Web版和标准版 Web版核心 Web版核心和标准版核心 从Windows Server 2008 (RC,IDS) 升级到Windows Server 2008 R2 数据中心版 数据中心版 数据中心版核心数据中心版核心 企业版 企业版和数据中心版 企业版核心 企业版核心和数据中心版核心 Foundation (SP2) 标准版 标准版 标准版和企业版 标准版核心 标准版核心和企业版核心 Web版Web版和标准版 Web版核心Web版核心和标准版核心 2.全新安装:即在一个全新的服务器上安装Windows Server 2008R2. 3.远程安装,此种安装模式用于批量安装windows server 2008R2,可以使用WDS或者其它方法安装,在后面的章节中会介绍。 4.Server Core安装,只安装核心的模块,Server Core模式不具有图形界面,所有的操作都是通过命令实现,主要用于安装DHCP,DNS等服务,稍后会介绍。 5.安装一个Windows Server 2008R2的步骤如下:限于篇幅,本文只简单将安装过程的截图放在下面。 此处若选择升级则为升级安装,如果选择自定义,其实就是全新的安装了。 这里的密码必须包含数字,大写字母,小写字母,特殊符号中的三种组合。 总结:Windows Server 2008必然成为以后的微软操作系统的趋势,因此,大家必须学会不同的方式安装Windows Server 2008系统。 本文转自 ningxiang00 51CTO博客,原文链接:http://blog.51cto.com/andygao/471569,如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册